<commit_before>use math::*;

pub type MeshIndex = u32;

/// The raw data representing a mesh in memory.
///
/// Meshes are represented as list of vertex positions and a list of faces.
/// Each face is represented as 3 indices into the vertex array.
#[derive(Debug, Clone)]
pub struct Mesh {
    vertex_data: Vec<f32>,
    indices:     Vec<MeshIndex>,

    position: VertexAttribute,
    normal:   Option<VertexAttribute>,
    texcoord: Vec<VertexAttribute>,
}

impl Mesh {
    pub fn vertex_data(&self) -> &[f32] {
        &*self.vertex_data
    }

    pub fn indices(&self) -> &[MeshIndex] {
        &*self.indices
    }

    pub fn position(&self) -> VertexAttribute {
        self.position
    }

    pub fn normal(&self) -> Option<VertexAttribute> {
        self.normal
    }

    pub fn texcoord(&self) -> &[VertexAttribute] {
        &*self.texcoord
    }
}

/// Represents a single vertex in a mesh with all of its supported attributes.
#[derive(Debug, Clone)]
pub struct Vertex {
    pub position: Point,
    pub normal: Option<Vector3>,

    /// Support an arbitrary number of texture units. The actual maximum is dependent on hardware
    /// and so is not limited by polygon directly. If the number of
    pub texcoord: Vec<Vector2>,
}

impl Vertex {
    pub fn new(position: Point) -> Vertex {
        Vertex {
            position: position,
            normal: None,
            texcoord: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct VertexAttribute {
    pub offset: usize,
    pub stride: usize,
}

#[derive(Debug, Clone, Copy)]
pub enum BuildMeshError {
    IndexOutOfBounds {
        vertex_count: MeshIndex,
        index: MeshIndex,
    },

    /// Indicates that one or more attributes had a count that did not match the total number of
    /// vertices.
    IncorrectAttributeCount,
}

/// Provides a safe interface for building a mesh from raw vertex data.
///
/// `MeshBuilder` supports two methods for specifying mesh data: Providing a series of `Vertex`
/// objects, or directly setting the data for each vertex attribute at once. Once all vertex data
/// has been set calling `build()` will validate the mesh data and produce a `Mesh` object.
///
/// The mesh builder performs validity tests when building the mesh and mesh compilation can fail
/// if the mesh data is invalid in some way. The following validity tests are performed:
///
/// - Check for different data count for different attributes (e.g. if the position attribute data
///   for a different number of elements than the normal attribute).
/// - Any of the indicies would be out of bounds for the given vertex data.
#[derive(Debug, Clone)]
pub struct MeshBuilder {
    position_data: Vec<Point>,
    normal_data: Vec<Vector3>,
    texcoord_data: Vec<Vector2>,

    indices:  Vec<u32>,
}

impl MeshBuilder {
    pub fn new() -> MeshBuilder {
        MeshBuilder {
            position_data: Vec::new(),
            normal_data:   Vec::new(),
            texcoord_data: Vec::new(),
            indices:       Vec::new(),
        }
    }

    pub fn add_vertex(&mut self, vertex: Vertex) {
        self.position_data.push(vertex.position);

        if let Some(normal) = vertex.normal {
            self.normal_data.push(normal);
        }

        assert!(vertex.texcoord.len() <= 1, "More than one texcoord per vertex is currently not supported");

        // Add each texcoord to its corresponding list.
        if vertex.texcoord.len() > 0 {
            self.texcoord_data.push(vertex.texcoord[0])
        }
    }

    pub fn add_index(mut self, index: MeshIndex) -> MeshBuilder {
        self.indices.push(index);
        self
    }

    pub fn set_position_data(mut self, position_data: &[Point]) -> MeshBuilder {
        self.position_data.clear();
        self.position_data.extend(position_data);
        self
    }

    pub fn set_normal_data(mut self, normal_data: &[Vector3]) -> MeshBuilder {
        self.normal_data.clear();
        self.normal_data.extend(normal_data);
        self
    }

    pub fn set_texcoord_data(mut self, texcoord_data: &[Vector2]) -> MeshBuilder {
        self.texcoord_data.clear();
        self.texcoord_data.extend(texcoord_data);
        self
    }

    pub fn set_indices(mut self, indices: &[u32]) -> MeshBuilder {
        self.indices.clear();
        self.indices.extend(indices);
        self
    }

    pub fn build(self) -> Result<Mesh, BuildMeshError> {
        // The vertex count is defined by the position data, since position is the only required
        // vertex attribute.
        let vertex_count = self.position_data.len();

        // Check that there is enough attribute data for each one.
        if self.normal_data.len() != 0 && self.normal_data.len() != vertex_count {
            return Err(BuildMeshError::IncorrectAttributeCount);
        }

        if self.texcoord_data.len() != vertex_count {
            return Err(BuildMeshError::IncorrectAttributeCount);
        }

        // Make sure all indices at least point to a valid vertex.
        for index in self.indices.iter().cloned() {
            if index >= vertex_count as MeshIndex {
                return Err(BuildMeshError::IndexOutOfBounds {
                    vertex_count: vertex_count as MeshIndex,
                    index: index,
                });
            }
        }

        // TODO: Check for degenerate triangles? Actually, should that be a failure or a warning?

        let float_count =
            self.position_data.len() * 4
          + self.normal_data.len() * 3
          + self.texcoord_data.len() * 2;

        // Create the mesh.
        let mut vertex_data = Vec::<f32>::with_capacity(float_count);

        // Setup position data.
        let position_attrib = VertexAttribute {
            offset: 0,
            stride: 4,
        };
        vertex_data.extend(Point::as_ref(&*self.position_data));

        // Setup normal data.
        let normal_attrib = if self.normal_data.len() > 0 {
            let attrib = VertexAttribute {
                offset: vertex_data.len(),
                stride: 3,
            };
            vertex_data.extend(Vector3::as_ref(&*self.normal_data));

            Some(attrib)
        } else {
            None
        };

        // Setup texcoord data.
        let mut texcoord_attribs = Vec::new();
        {
            texcoord_attribs.push(VertexAttribute {
                offset: vertex_data.len(),
                stride: 2,
            });
            vertex_data.extend(Vector2::as_ref(&*self.texcoord_data));
        }

        // By our powers combined! We are! A mesh.
        Ok(Mesh {
            vertex_data: vertex_data,
            indices: self.indices,

            position: position_attrib,
            normal: normal_attrib,
            texcoord: texcoord_attribs,
        })
    }
}
<commit_msg>Fix Bug In Mesh Validation<commit_after>use math::*;

pub type MeshIndex = u32;

/// The raw data representing a mesh in memory.
///
/// Meshes are represented as list of vertex positions and a list of faces.
/// Each face is represented as 3 indices into the vertex array.
#[derive(Debug, Clone)]
pub struct Mesh {
    vertex_data: Vec<f32>,
    indices:     Vec<MeshIndex>,

    position: VertexAttribute,
    normal:   Option<VertexAttribute>,
    texcoord: Vec<VertexAttribute>,
}

impl Mesh {
    pub fn vertex_data(&self) -> &[f32] {
        &*self.vertex_data
    }

    pub fn indices(&self) -> &[MeshIndex] {
        &*self.indices
    }

    pub fn position(&self) -> VertexAttribute {
        self.position
    }

    pub fn normal(&self) -> Option<VertexAttribute> {
        self.normal
    }

    pub fn texcoord(&self) -> &[VertexAttribute] {
        &*self.texcoord
    }
}

/// Represents a single vertex in a mesh with all of its supported attributes.
#[derive(Debug, Clone)]
pub struct Vertex {
    pub position: Point,
    pub normal: Option<Vector3>,

    /// Support an arbitrary number of texture units. The actual maximum is dependent on hardware
    /// and so is not limited by polygon directly. If the number of
    pub texcoord: Vec<Vector2>,
}

impl Vertex {
    pub fn new(position: Point) -> Vertex {
        Vertex {
            position: position,
            normal: None,
            texcoord: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct VertexAttribute {
    pub offset: usize,
    pub stride: usize,
}

#[derive(Debug, Clone, Copy)]
pub enum BuildMeshError {
    IndexOutOfBounds {
        vertex_count: MeshIndex,
        index: MeshIndex,
    },

    /// Indicates that one or more attributes had a count that did not match the total number of
    /// vertices.
    IncorrectAttributeCount {
        attribute: VertexAttributeType,
        expected: usize,
        actual: usize,
    },
}

#[derive(Debug, Clone, Copy)]
pub enum VertexAttributeType {
    Position,
    Normal,
    Texcoord,
}

/// Provides a safe interface for building a mesh from raw vertex data.
///
/// `MeshBuilder` supports two methods for specifying mesh data: Providing a series of `Vertex`
/// objects, or directly setting the data for each vertex attribute at once. Once all vertex data
/// has been set calling `build()` will validate the mesh data and produce a `Mesh` object.
///
/// The mesh builder performs validity tests when building the mesh and mesh compilation can fail
/// if the mesh data is invalid in some way. The following validity tests are performed:
///
/// - Check for different data count for different attributes (e.g. if the position attribute data
///   for a different number of elements than the normal attribute).
/// - Any of the indicies would be out of bounds for the given vertex data.
#[derive(Debug, Clone)]
pub struct MeshBuilder {
    position_data: Vec<Point>,
    normal_data: Vec<Vector3>,
    texcoord_data: Vec<Vector2>,

    indices:  Vec<u32>,
}

impl MeshBuilder {
    pub fn new() -> MeshBuilder {
        MeshBuilder {
            position_data: Vec::new(),
            normal_data:   Vec::new(),
            texcoord_data: Vec::new(),
            indices:       Vec::new(),
        }
    }

    pub fn add_vertex(&mut self, vertex: Vertex) {
        self.position_data.push(vertex.position);

        if let Some(normal) = vertex.normal {
            self.normal_data.push(normal);
        }

        assert!(vertex.texcoord.len() <= 1, "More than one texcoord per vertex is currently not supported");

        // Add each texcoord to its corresponding list.
        if vertex.texcoord.len() > 0 {
            self.texcoord_data.push(vertex.texcoord[0])
        }
    }

    pub fn add_index(mut self, index: MeshIndex) -> MeshBuilder {
        self.indices.push(index);
        self
    }

    pub fn set_position_data(mut self, position_data: &[Point]) -> MeshBuilder {
        self.position_data.clear();
        self.position_data.extend(position_data);
        self
    }

    pub fn set_normal_data(mut self, normal_data: &[Vector3]) -> MeshBuilder {
        self.normal_data.clear();
        self.normal_data.extend(normal_data);
        self
    }

    pub fn set_texcoord_data(mut self, texcoord_data: &[Vector2]) -> MeshBuilder {
        self.texcoord_data.clear();
        self.texcoord_data.extend(texcoord_data);
        self
    }

    pub fn set_indices(mut self, indices: &[u32]) -> MeshBuilder {
        self.indices.clear();
        self.indices.extend(indices);
        self
    }

    pub fn build(self) -> Result<Mesh, BuildMeshError> {
        // The vertex count is defined by the position data, since position is the only required
        // vertex attribute.
        let vertex_count = self.position_data.len();

        // Check that there is enough attribute data for each one.
        if self.normal_data.len() != 0 && self.normal_data.len() != vertex_count {
            return Err(BuildMeshError::IncorrectAttributeCount {
                attribute: VertexAttributeType::Normal,
                expected: vertex_count,
                actual: self.normal_data.len(),
            });
        }

        if self.texcoord_data.len() != 0 && self.texcoord_data.len() != vertex_count {
            return Err(BuildMeshError::IncorrectAttributeCount {
                attribute: VertexAttributeType::Texcoord,
                expected: vertex_count,
                actual: self.texcoord_data.len(),
            });
        }

        // Make sure all indices at least point to a valid vertex.
        for index in self.indices.iter().cloned() {
            if index >= vertex_count as MeshIndex {
                return Err(BuildMeshError::IndexOutOfBounds {
                    vertex_count: vertex_count as MeshIndex,
                    index: index,
                });
            }
        }

        // TODO: Check for degenerate triangles? Actually, should that be a failure or a warning?

        let float_count =
            self.position_data.len() * 4
          + self.normal_data.len() * 3
          + self.texcoord_data.len() * 2;

        // Create the mesh.
        let mut vertex_data = Vec::<f32>::with_capacity(float_count);

        // Setup position data.
        let position_attrib = VertexAttribute {
            offset: 0,
            stride: 4,
        };
        vertex_data.extend(Point::as_ref(&*self.position_data));

        // Setup normal data.
        let normal_attrib = if self.normal_data.len() > 0 {
            let attrib = VertexAttribute {
                offset: vertex_data.len(),
                stride: 3,
            };
            vertex_data.extend(Vector3::as_ref(&*self.normal_data));

            Some(attrib)
        } else {
            None
        };

        // Setup texcoord data.
        let mut texcoord_attribs = Vec::new();
        {
            texcoord_attribs.push(VertexAttribute {
                offset: vertex_data.len(),
                stride: 2,
            });
            vertex_data.extend(Vector2::as_ref(&*self.texcoord_data));
        }

        // By our powers combined! We are! A mesh.
        Ok(Mesh {
            vertex_data: vertex_data,
            indices: self.indices,

            position: position_attrib,
            normal: normal_attrib,
            texcoord: texcoord_attribs,
        })
    }
}
<|endoftext|>


<commit_before>use super::ssz::decode::{
    decode_length,
    Decodable,
};
use super::utils::hash::canonical_hash;
use super::block::{
    MIN_SSZ_BLOCK_LENGTH,
    MAX_SSZ_BLOCK_LENGTH,
};
use super::attestation_record::MIN_SSZ_ATTESTION_RECORD_LENGTH;

#[derive(Debug, PartialEq)]
pub enum BlockValidatorError {
    TooShort,
    TooLong,
    BadPowHash,
    SlotTooLow,
    SlotTooHigh,
}

const LENGTH_BYTES: usize = 4;

/// Allows for reading of block values directly from serialized
/// ssz bytes.
///
/// Use this to perform intial checks before we fully de-serialize
/// a block. It should only really be used to verify blocks that come
/// in from the network, for internal operations we should use a full
/// `Block`.
#[derive(Debug, PartialEq)]
pub struct SszBlock<'a> {
    ssz: &'a [u8],
    attestation_len: usize,
    pub len: usize,
}

impl<'a> SszBlock<'a> {
    /// Create a new instance from a slice reference.
    ///
    /// This function will validate the length of the ssz
    /// string, however it will not validate the contents.
    ///
    /// The slice will not be copied, instead referenced.
    pub fn from_slice(vec: &'a [u8])
        -> Result<Self, BlockValidatorError>
    {
        let untrimmed_ssz = &vec[..];
        /*
         * Ensure the SSZ is long enough to be a block with
         * one attestation record (not necessarily a valid
         * attestation record).
         */
        if vec.len() < MIN_SSZ_BLOCK_LENGTH + MIN_SSZ_ATTESTION_RECORD_LENGTH {
            return Err(BlockValidatorError::TooShort);
        }
        /*
         * Ensure the SSZ slice isn't longer than is possible for a block.
         */
        if vec.len() > MAX_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::TooLong);
        }
        /*
         * Determine how many bytes are used to store attestation records.
         */
        let attestation_len = decode_length(untrimmed_ssz, 80, LENGTH_BYTES)
            .map_err(|_| BlockValidatorError::TooShort)?;
        /*
         * The block only has one variable field, `attestations`, therefore
         * the size of the block must be the minimum size, plus the length
         * of the attestations.
         */
        let block_ssz_len = {
            MIN_SSZ_BLOCK_LENGTH + attestation_len
        };
        if vec.len() < block_ssz_len {
            return Err(BlockValidatorError::TooShort);
        }
        Ok(Self{
            ssz: &untrimmed_ssz[0..block_ssz_len],
            attestation_len,
            len: block_ssz_len,
        })
    }

    /// Return the canonical hash for this block.
    pub fn block_hash(&self) -> Vec<u8> {
        canonical_hash(self.ssz)
    }

    /// Return the `parent_hash` field.
    pub fn parent_hash(&self) -> &[u8] {
        &self.ssz[4..36]
    }

    /// Return the `slot_number` field.
    pub fn slot_number(&self) -> u64 {
        /*
         * An error should be unreachable from this decode
         * because we checked the length of the array at
         * the initalization of this struct.
         *
         * If you can make this function panic, please report
         * it to paul@sigmaprime.io
         */
        if let Ok((n, _)) = u64::ssz_decode(&self.ssz, 36) {
            n
        } else {
            unreachable!();
        }
    }

    /// Return the `randao_reveal` field.
    pub fn randao_reveal(&self) -> &[u8] {
        &self.ssz[48..80]
    }

    /// Return the `attestations` field.
    pub fn attestations(&self) -> &[u8] {
        let start = 80 + LENGTH_BYTES;
        &self.ssz[start..(start + self.attestation_len)]
    }

    /// Return the `pow_chain_ref` field.
    pub fn pow_chain_ref(&self) -> &[u8] {
        let start = self.len - (32 + LENGTH_BYTES + 32 + LENGTH_BYTES + 32);
        &self.ssz[start..(start + 32)]
    }

    /// Return the `active_state_root` field.
    pub fn act_state_root(&self) -> &[u8] {
        let start = self.len - (32 + LENGTH_BYTES + 32);
        &self.ssz[start..(start + 32)]
    }

    /// Return the `active_state_root` field.
    pub fn cry_state_root(&self) -> &[u8] {
        let start = self.len - 32;
        &self.ssz[start..(start + 32)]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::block::Block;
    use super::super::attestation_record::AttestationRecord;
    use super::super::ssz::SszStream;
    use super::super::utils::types::Hash256;

    fn get_block_ssz(b: &Block) -> Vec<u8> {
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(b);
        ssz_stream.drain()
    }

    fn get_attestation_record_ssz(ar: &AttestationRecord) -> Vec<u8> {
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(ar);
        ssz_stream.drain()
    }

    #[test]
    fn test_ssz_block_zero_attestation_records() {
        let mut b = Block::zero();
        b.attestations = vec![];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[..]),
            Err(BlockValidatorError::TooShort)
        );
    }

    #[test]
    fn test_ssz_block_single_attestation_record_one_byte_short() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[0..(ssz.len() - 1)]),
            Err(BlockValidatorError::TooShort)
        );
    }

    #[test]
    fn test_ssz_block_single_attestation_record_one_byte_long() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let mut ssz = get_block_ssz(&b);
        let original_len = ssz.len();
        ssz.push(42);

        let ssz_block = SszBlock::from_slice(&ssz[..]).unwrap();

        assert_eq!(ssz_block.len, original_len);
    }

    #[test]
    fn test_ssz_block_single_attestation_record() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let ssz = get_block_ssz(&b);

        assert!(SszBlock::from_slice(&ssz[..]).is_ok());
    }

    #[test]
    fn test_ssz_block_block_hash() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();
        let hash = ssz_block.block_hash();
        // Note: this hash was not generated by some external program,
        // it was simply printed then copied into the code. This test
        // will tell us if the hash changes, not that it matches some
        // canonical reference.
        let expected_hash = [
            28, 184, 51, 12, 226, 15, 73, 50, 66, 19, 168, 149,
            229, 122, 141, 111, 42, 236, 137, 157, 230, 90, 149,
            58, 145, 52, 47, 62, 158, 131, 46, 147
        ];
        assert_eq!(hash, expected_hash);
    }

    #[test]
    fn test_ssz_block_parent_hash() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.parent_hash = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.parent_hash(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_slot_number() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        block.slot_number = 42;

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.slot_number(), 42);
    }

    #[test]
    fn test_ssz_block_randao_reveal() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.randao_reveal = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.randao_reveal(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_attestations() {
        /*
         * Single AttestationRecord
         */
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();
        let ssz_ar = get_attestation_record_ssz(&AttestationRecord::zero());

        assert_eq!(ssz_block.attestations(), &ssz_ar[..]);

        /*
         * Multiple AttestationRecords
         */
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        block.attestations.push(AttestationRecord::zero());

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();
        let mut ssz_ar = get_attestation_record_ssz(&AttestationRecord::zero());
        ssz_ar.append(&mut get_attestation_record_ssz(&AttestationRecord::zero()));

        assert_eq!(ssz_block.attestations(), &ssz_ar[..]);
    }

    #[test]
    fn test_ssz_block_pow_chain_ref() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.pow_chain_ref = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.pow_chain_ref(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_act_state_root() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.active_state_root = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.act_state_root(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_cry_state_root() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.crystallized_state_root = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.cry_state_root(), &reference_hash.to_vec()[..]);
    }
}
<commit_msg>Add SszBlock test to check the canonical hash<commit_after>use super::ssz::decode::{
    decode_length,
    Decodable,
};
use super::utils::hash::canonical_hash;
use super::block::{
    MIN_SSZ_BLOCK_LENGTH,
    MAX_SSZ_BLOCK_LENGTH,
};
use super::attestation_record::MIN_SSZ_ATTESTION_RECORD_LENGTH;

#[derive(Debug, PartialEq)]
pub enum BlockValidatorError {
    TooShort,
    TooLong,
    BadPowHash,
    SlotTooLow,
    SlotTooHigh,
}

const LENGTH_BYTES: usize = 4;

/// Allows for reading of block values directly from serialized
/// ssz bytes.
///
/// Use this to perform intial checks before we fully de-serialize
/// a block. It should only really be used to verify blocks that come
/// in from the network, for internal operations we should use a full
/// `Block`.
#[derive(Debug, PartialEq)]
pub struct SszBlock<'a> {
    ssz: &'a [u8],
    attestation_len: usize,
    pub len: usize,
}

impl<'a> SszBlock<'a> {
    /// Create a new instance from a slice reference.
    ///
    /// This function will validate the length of the ssz
    /// string, however it will not validate the contents.
    ///
    /// The slice will not be copied, instead referenced.
    pub fn from_slice(vec: &'a [u8])
        -> Result<Self, BlockValidatorError>
    {
        let untrimmed_ssz = &vec[..];
        /*
         * Ensure the SSZ is long enough to be a block with
         * one attestation record (not necessarily a valid
         * attestation record).
         */
        if vec.len() < MIN_SSZ_BLOCK_LENGTH + MIN_SSZ_ATTESTION_RECORD_LENGTH {
            return Err(BlockValidatorError::TooShort);
        }
        /*
         * Ensure the SSZ slice isn't longer than is possible for a block.
         */
        if vec.len() > MAX_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::TooLong);
        }
        /*
         * Determine how many bytes are used to store attestation records.
         */
        let attestation_len = decode_length(untrimmed_ssz, 80, LENGTH_BYTES)
            .map_err(|_| BlockValidatorError::TooShort)?;
        /*
         * The block only has one variable field, `attestations`, therefore
         * the size of the block must be the minimum size, plus the length
         * of the attestations.
         */
        let block_ssz_len = {
            MIN_SSZ_BLOCK_LENGTH + attestation_len
        };
        if vec.len() < block_ssz_len {
            return Err(BlockValidatorError::TooShort);
        }
        Ok(Self{
            ssz: &untrimmed_ssz[0..block_ssz_len],
            attestation_len,
            len: block_ssz_len,
        })
    }

    /// Return the canonical hash for this block.
    pub fn block_hash(&self) -> Vec<u8> {
        canonical_hash(self.ssz)
    }

    /// Return the `parent_hash` field.
    pub fn parent_hash(&self) -> &[u8] {
        &self.ssz[4..36]
    }

    /// Return the `slot_number` field.
    pub fn slot_number(&self) -> u64 {
        /*
         * An error should be unreachable from this decode
         * because we checked the length of the array at
         * the initalization of this struct.
         *
         * If you can make this function panic, please report
         * it to paul@sigmaprime.io
         */
        if let Ok((n, _)) = u64::ssz_decode(&self.ssz, 36) {
            n
        } else {
            unreachable!();
        }
    }

    /// Return the `randao_reveal` field.
    pub fn randao_reveal(&self) -> &[u8] {
        &self.ssz[48..80]
    }

    /// Return the `attestations` field.
    pub fn attestations(&self) -> &[u8] {
        let start = 80 + LENGTH_BYTES;
        &self.ssz[start..(start + self.attestation_len)]
    }

    /// Return the `pow_chain_ref` field.
    pub fn pow_chain_ref(&self) -> &[u8] {
        let start = self.len - (32 + LENGTH_BYTES + 32 + LENGTH_BYTES + 32);
        &self.ssz[start..(start + 32)]
    }

    /// Return the `active_state_root` field.
    pub fn act_state_root(&self) -> &[u8] {
        let start = self.len - (32 + LENGTH_BYTES + 32);
        &self.ssz[start..(start + 32)]
    }

    /// Return the `active_state_root` field.
    pub fn cry_state_root(&self) -> &[u8] {
        let start = self.len - 32;
        &self.ssz[start..(start + 32)]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::block::Block;
    use super::super::attestation_record::AttestationRecord;
    use super::super::ssz::SszStream;
    use super::super::utils::types::Hash256;

    fn get_block_ssz(b: &Block) -> Vec<u8> {
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(b);
        ssz_stream.drain()
    }

    fn get_attestation_record_ssz(ar: &AttestationRecord) -> Vec<u8> {
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(ar);
        ssz_stream.drain()
    }

    #[test]
    fn test_ssz_block_zero_attestation_records() {
        let mut b = Block::zero();
        b.attestations = vec![];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[..]),
            Err(BlockValidatorError::TooShort)
        );
    }

    #[test]
    fn test_ssz_block_single_attestation_record_one_byte_short() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[0..(ssz.len() - 1)]),
            Err(BlockValidatorError::TooShort)
        );
    }

    #[test]
    fn test_ssz_block_single_attestation_record_one_byte_long() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let mut ssz = get_block_ssz(&b);
        let original_len = ssz.len();
        ssz.push(42);

        let ssz_block = SszBlock::from_slice(&ssz[..]).unwrap();

        assert_eq!(ssz_block.len, original_len);
    }

    #[test]
    fn test_ssz_block_single_attestation_record() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let ssz = get_block_ssz(&b);

        assert!(SszBlock::from_slice(&ssz[..]).is_ok());
    }

    #[test]
    fn test_ssz_block_block_hash() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();
        let hash = ssz_block.block_hash();
        // Note: this hash was not generated by some external program,
        // it was simply printed then copied into the code. This test
        // will tell us if the hash changes, not that it matches some
        // canonical reference.
        let expected_hash = [
            28, 184, 51, 12, 226, 15, 73, 50, 66, 19, 168, 149,
            229, 122, 141, 111, 42, 236, 137, 157, 230, 90, 149,
            58, 145, 52, 47, 62, 158, 131, 46, 147
        ];
        assert_eq!(hash, expected_hash);

        /*
         * Test if you give the SszBlock too many ssz bytes
         */
        let mut too_long = serialized.clone();
        too_long.push(42);
        let ssz_block = SszBlock::from_slice(&too_long).unwrap();
        let hash = ssz_block.block_hash();
        assert_eq!(hash, expected_hash);
    }

    #[test]
    fn test_ssz_block_parent_hash() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.parent_hash = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.parent_hash(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_slot_number() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        block.slot_number = 42;

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.slot_number(), 42);
    }

    #[test]
    fn test_ssz_block_randao_reveal() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.randao_reveal = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.randao_reveal(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_attestations() {
        /*
         * Single AttestationRecord
         */
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();
        let ssz_ar = get_attestation_record_ssz(&AttestationRecord::zero());

        assert_eq!(ssz_block.attestations(), &ssz_ar[..]);

        /*
         * Multiple AttestationRecords
         */
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        block.attestations.push(AttestationRecord::zero());

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();
        let mut ssz_ar = get_attestation_record_ssz(&AttestationRecord::zero());
        ssz_ar.append(&mut get_attestation_record_ssz(&AttestationRecord::zero()));

        assert_eq!(ssz_block.attestations(), &ssz_ar[..]);
    }

    #[test]
    fn test_ssz_block_pow_chain_ref() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.pow_chain_ref = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.pow_chain_ref(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_act_state_root() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.active_state_root = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.act_state_root(), &reference_hash.to_vec()[..]);
    }

    #[test]
    fn test_ssz_block_cry_state_root() {
        let mut block = Block::zero();
        block.attestations.push(AttestationRecord::zero());
        let reference_hash = Hash256::from([42_u8; 32]);
        block.crystallized_state_root = reference_hash.clone();

        let serialized = get_block_ssz(&block);
        let ssz_block = SszBlock::from_slice(&serialized).unwrap();

        assert_eq!(ssz_block.cry_state_root(), &reference_hash.to_vec()[..]);
    }
}
<|endoftext|>


<commit_before>use system::*;

pub struct TileMap
{
    pub tiles: Vec<TileData>,
    pub map: Vec<u8>,
}

impl TileMap {
     pub fn new() -> TileMap
     {
         return TileMap
         {
             tiles: vec![TileData::new();256],
             map: vec![0, 1024],
         }
     }

     pub fn populate_tile_map(&mut self, system_data_original: &mut SystemData, lcdc_data_select: u8, lcdc_display_select: u8)
     {
        let mut system_data = system_data_original;
        for tile_index in 0..self.tiles.len()
        {
            self.tiles[tile_index] = get_tile_data(tile_index as u8, &mut system_data, lcdc_data_select);
        }

        self.map = self.vectorize_map(&mut system_data, lcdc_display_select);
     }

     fn vectorize_map(&mut self, system_data: &mut SystemData, lcdc_display_select: u8) -> Vec<u8>
     {
        let mut map: Vec<u8> = vec![0;1024];
        let mut map_offset: u16 = 0;
        if lcdc_display_select == 1
        {
            map_offset = 0x9C00;
        }
        else {
            map_offset = 0x9800;
        }

        for i in 0..map.len()
        {
            map[i] = system_data.mem_map[map_offset as usize + i];
        }

        return map
     }
}

#[derive(Clone)]
pub struct TileData
{
    pub data: Vec<u8>,
}

impl TileData
{
    pub fn new() -> TileData
    {
        return TileData
        {
            data: vec![0; 64],
        }
    }
}

pub fn get_tile_data(tile_index: u8, system_data: &mut SystemData, lcdc_data_select: u8) -> TileData
{
    let mut tile_data = TileData::new();
    let mut vram_offset: u16 = 0;

    if lcdc_data_select == 1
    {
        vram_offset = 0x8000;
    }
    else {
        vram_offset = 0x8800
    }

    let mem_loc: u16 = vram_offset + (tile_index as u16 * 16);
    for byte_pair in 0..8
    {
        for bit in 0..8
        {
            let upper_bit: u8 = (system_data.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize] >> (7 - bit)) & 0x01;
            let lower_bit: u8 = (system_data.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize + 1] >> (7 - bit)) & 0x01;
            tile_data.data[(byte_pair as usize * 8) + bit as usize] = (upper_bit << 1) | lower_bit;
        }
    }
    return tile_data;
}

pub fn update_gpu(system_data_original: &mut SystemData, registers_original: &mut Registers, gpu_registers_original: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let mut gpu_registers = gpu_registers_original;
    LCD_Y_Coordinate_Update(&mut system_data, &mut gpu_registers);
}

pub fn LCD_Y_Coordinate_Update(system_data: &mut SystemData, gpu_registers: &mut GPU_Registers)
{
    gpu_registers.ly_cycle_count += system_data.cycles as u32;
    gpu_registers.ly_sub_cycle_count += system_data.cycles as u16;
    if (gpu_registers.ly_cycle_count >= 70224)
    {
        gpu_registers.ly_cycle_count -= 70224;
    }
    if (gpu_registers.ly_sub_cycle_count >= 456)
    {
        gpu_registers.ly_register += 1;
        if gpu_registers.ly_register == 154
        {
            gpu_registers.ly_register = 0;
        }
        system_data.mem_map[0xFF44] = gpu_registers.ly_register;
        gpu_registers.ly_sub_cycle_count -= 456;
    }
}

#[cfg(test)]
mod gpu_tests
{
    use system::get_system_data;
    use gpu::gpu::*;

    #[test]
    fn get_tile_data_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));

        let temp_memory_values : Vec<u8> = vec![0b00001111, 0b00110011, 0b11110000, 0b11001100];

        for vram_offset in vec![0x8000, 0x8800].iter()
        {
            for i in 0..temp_memory_values.len()
            {
                system_data.mem_map[*vram_offset + i] = temp_memory_values[i];
            }
        }
        let tiles = vec![get_tile_data(0, &mut system_data, 0), get_tile_data(0, &mut system_data, 1)];
        for tile in tiles.iter()
        {
            for i in 0..4
            {
                assert_eq!(tile.data[i as usize * 2], i);
                assert_eq!(tile.data[(i as usize * 2) + 1 ], i);
                assert_eq!(tile.data[8 + (i as usize * 2)], 3 - i);
                assert_eq!(tile.data[(8 + (i as usize * 2)) + 1], 3 - i);
            }
        }
    }

    #[test]
    fn get_tile_map() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut TileMap = TileMap::new();

        TileMap.populate_tile_map(&mut system_data, 1, 1);
        for i in 0..TileMap.tiles.len()
        {
            for j in 0..64
            {
                assert_eq!(TileMap.tiles[i].data[j], 0);
            }
        }
        for i in 0..0x1000{
            system_data.mem_map[0x8000 + i] = 0xFF;
        }
        TileMap.populate_tile_map(&mut system_data, 1, 1);
        for i in 0..TileMap.tiles.len()
        {
            for j in 0..64
            {
                assert_eq!(TileMap.tiles[i].data[j], 3);
            }
        }
        for i in 0..0x800{
            system_data.mem_map[0x8800 + i] = 0x00;
        }
        TileMap.populate_tile_map(&mut system_data, 0, 1);
        for i in 0..TileMap.tiles.len()
        {
            for j in 0..64
            {
                assert_eq!(TileMap.tiles[i].data[j], 0);
            }
        }
        for i in 0..0x1000{
            system_data.mem_map[0x8800 + i] = 0xFF;
        }
        TileMap.populate_tile_map(&mut system_data, 0, 1);
        for i in 0..TileMap.tiles.len()
        {
            for j in 0..64
            {
                assert_eq!(TileMap.tiles[i].data[j], 3);
            }
        }

        TileMap.populate_tile_map(&mut system_data, 0, 1);
        for i in 0..TileMap.map.len()
        {
            assert_eq!(TileMap.map[i], 0);
        }
        for i in 0..TileMap.map.len(){
            system_data.mem_map[0x9C00 + i] = 0xFF;
        }
        TileMap.populate_tile_map(&mut system_data, 0, 1);
        for i in 0..TileMap.map.len()
        {
            assert_eq!(TileMap.map[i], 0xFF);
        }

        TileMap.populate_tile_map(&mut system_data, 0, 0);
        for i in 0..TileMap.map.len()
        {
            assert_eq!(TileMap.map[i], 0);
        }
        for i in 0..TileMap.map.len(){
            system_data.mem_map[0x9800 + i] = 0xFF;
        }
        TileMap.populate_tile_map(&mut system_data, 0, 0);
        for i in 0..TileMap.map.len()
        {
            assert_eq!(TileMap.map[i], 0xFF);
        }
    }

}
<commit_msg>Cleaned tile_map test<commit_after>use system::*;

pub struct TileMap
{
    pub tiles: Vec<TileData>,
    pub map: Vec<u8>,
}

impl TileMap {
     pub fn new() -> TileMap
     {
         return TileMap
         {
             tiles: vec![TileData::new();256],
             map: vec![0, 1024],
         }
     }

     pub fn populate_tile_map(&mut self, system_data_original: &mut SystemData, lcdc_data_select: u8, lcdc_display_select: u8)
     {
        let mut system_data = system_data_original;
        for tile_index in 0..self.tiles.len()
        {
            self.tiles[tile_index] = get_tile_data(tile_index as u8, &mut system_data, lcdc_data_select);
        }

        self.map = self.vectorize_map(&mut system_data, lcdc_display_select);
     }

     fn vectorize_map(&mut self, system_data: &mut SystemData, lcdc_display_select: u8) -> Vec<u8>
     {
        let mut map: Vec<u8> = vec![0;1024];
        let mut map_offset: u16 = 0;
        if lcdc_display_select == 1
        {
            map_offset = 0x9C00;
        }
        else {
            map_offset = 0x9800;
        }

        for i in 0..map.len()
        {
            map[i] = system_data.mem_map[map_offset as usize + i];
        }

        return map
     }
}

#[derive(Clone)]
pub struct TileData
{
    pub data: Vec<u8>,
}

impl TileData
{
    pub fn new() -> TileData
    {
        return TileData
        {
            data: vec![0; 64],
        }
    }
}

pub fn get_tile_data(tile_index: u8, system_data: &mut SystemData, lcdc_data_select: u8) -> TileData
{
    let mut tile_data = TileData::new();
    let mut vram_offset: u16 = 0;

    if lcdc_data_select == 1
    {
        vram_offset = 0x8000;
    }
    else {
        vram_offset = 0x8800
    }

    let mem_loc: u16 = vram_offset + (tile_index as u16 * 16);
    for byte_pair in 0..8
    {
        for bit in 0..8
        {
            let upper_bit: u8 = (system_data.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize] >> (7 - bit)) & 0x01;
            let lower_bit: u8 = (system_data.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize + 1] >> (7 - bit)) & 0x01;
            tile_data.data[(byte_pair as usize * 8) + bit as usize] = (upper_bit << 1) | lower_bit;
        }
    }
    return tile_data;
}

pub fn update_gpu(system_data_original: &mut SystemData, registers_original: &mut Registers, gpu_registers_original: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let mut gpu_registers = gpu_registers_original;
    LCD_Y_Coordinate_Update(&mut system_data, &mut gpu_registers);
}

pub fn LCD_Y_Coordinate_Update(system_data: &mut SystemData, gpu_registers: &mut GPU_Registers)
{
    gpu_registers.ly_cycle_count += system_data.cycles as u32;
    gpu_registers.ly_sub_cycle_count += system_data.cycles as u16;
    if (gpu_registers.ly_cycle_count >= 70224)
    {
        gpu_registers.ly_cycle_count -= 70224;
    }
    if (gpu_registers.ly_sub_cycle_count >= 456)
    {
        gpu_registers.ly_register += 1;
        if gpu_registers.ly_register == 154
        {
            gpu_registers.ly_register = 0;
        }
        system_data.mem_map[0xFF44] = gpu_registers.ly_register;
        gpu_registers.ly_sub_cycle_count -= 456;
    }
}

#[cfg(test)]
mod gpu_tests
{
    use system::get_system_data;
    use gpu::gpu::*;

    #[test]
    fn get_tile_data_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));

        let temp_memory_values : Vec<u8> = vec![0b00001111, 0b00110011, 0b11110000, 0b11001100];

        for vram_offset in vec![0x8000, 0x8800].iter()
        {
            for i in 0..temp_memory_values.len()
            {
                system_data.mem_map[*vram_offset + i] = temp_memory_values[i];
            }
        }
        let tiles = vec![get_tile_data(0, &mut system_data, 0), get_tile_data(0, &mut system_data, 1)];
        for tile in tiles.iter()
        {
            for i in 0..4
            {
                assert_eq!(tile.data[i as usize * 2], i);
                assert_eq!(tile.data[(i as usize * 2) + 1 ], i);
                assert_eq!(tile.data[8 + (i as usize * 2)], 3 - i);
                assert_eq!(tile.data[(8 + (i as usize * 2)) + 1], 3 - i);
            }
        }
    }

    #[test]
    fn get_tile_map_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut TileMap = TileMap::new();

        let memory_values: Vec<u8> = vec![0x00, 0xFF];
        let test_values: Vec<u8> = vec![0, 3];
        let tiles_offset: Vec<usize> = vec![0x8800, 0x8000];

        for offset_index in 0..tiles_offset.len()
        {
            for index in 0..test_values.len()
            {
                for i in 0..0x1000
                {
                    system_data.mem_map[tiles_offset[offset_index] + i] = memory_values[index];
                }

                TileMap.populate_tile_map(&mut system_data, offset_index as u8, 1);

                for i in 0..TileMap.tiles.len()
                {
                    for j in 0..64
                    {
                        assert_eq!(TileMap.tiles[i].data[j], test_values[index]);
                    }
                }
            }
        }

        let display_offset: Vec<usize> = vec![0x9800, 0x9C00];

        for offset_index in 0..display_offset.len()
        {
            for value_index in 0..memory_values.len()
            {
                for i in 0..TileMap.map.len()
                {
                    system_data.mem_map[display_offset[offset_index] + i] = memory_values[value_index];
                }

                TileMap.populate_tile_map(&mut system_data, 0, offset_index as u8);

                for i in 0..TileMap.map.len()
                {
                    assert_eq!(TileMap.map[i], memory_values[value_index]);
                }
            }
        }

    }

}
<|endoftext|>


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

use library::*;
use parser::is_empty_c_type;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index.iter().filter_map(|(name, &id)| {
            if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            }
        }).collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index.iter().flat_map(|(name, &id)| {
            let name = name.clone();
            self.namespace(id).unresolved().into_iter().map(move |s| format!("{}.{}", name, s))
        }).collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();  //Always contains something
                let tid = TypeId { ns_id: ns_id as u16, id: id as u32 };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) { return }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) =>
                    update_empty_signals_c_types(&mut klass.signals, &c_types),
                Type::Interface(ref mut iface) =>
                    update_empty_signals_c_types(&mut iface.signals, &c_types),
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(&self, signals: &[Signal], c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) { detected = true; }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) { detected = true; }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types)  { detected = true; }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) { return false }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let glib_name = self.type_(tid).get_glib_name();
        if glib_name.is_none() { return None; }
        let detected_c_type = format!("{}*", glib_name.unwrap());
        Some(detected_c_type)
    }
}
<commit_msg>Fix detecting empty c_type's<commit_after>use std::collections::HashMap;

use library::*;
use parser::is_empty_c_type;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index.iter().filter_map(|(name, &id)| {
            if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            }
        }).collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index.iter().flat_map(|(name, &id)| {
            let name = name.clone();
            self.namespace(id).unresolved().into_iter().map(move |s| format!("{}.{}", name, s))
        }).collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();  //Always contains something
                let tid = TypeId { ns_id: ns_id as u16, id: id as u32 };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) { return }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) =>
                    update_empty_signals_c_types(&mut klass.signals, &c_types),
                Type::Interface(ref mut iface) =>
                    update_empty_signals_c_types(&mut iface.signals, &c_types),
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(&self, signals: &[Signal], c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) { detected = true; }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) { detected = true; }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types)  { detected = true; }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) { return false }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        use library::Type::*;
        let type_ = self.type_(tid);
        let glib_name = type_.get_glib_name();
        if glib_name.is_none() { return None; }
        let glib_name = glib_name.unwrap();
        let detected_c_type = match *type_ {
            Record(..) |
            Class(..) |
            Interface(..) => format!("{}*", glib_name),
            _ => glib_name.to_string(),
        };
        Some(detected_c_type)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(missing_docs, nonstandard_style)]

use crate::io::ErrorKind;

pub use self::rand::hashmap_random_keys;
pub use crate::os::vxworks as platform;
pub use libc::strlen;

pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
pub mod thread_local;
pub mod time;

pub use crate::sys_common::os_str_bytes as os_str;

#[cfg(not(test))]
pub fn init() {
    // By default, some platforms will send a *signal* when an EPIPE error
    // would otherwise be delivered. This runtime doesn't install a SIGPIPE
    // handler, causing it to kill the program, which isn't exactly what we
    // want!
    //
    // Hence, we set SIGPIPE to ignore when the program starts up in order
    // to prevent this problem.
    unsafe {
        reset_sigpipe();
    }

    unsafe fn reset_sigpipe() {}
}

pub use libc::signal;

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as libc::c_int {
        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
        libc::ECONNRESET => ErrorKind::ConnectionReset,
        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
        libc::EPIPE => ErrorKind::BrokenPipe,
        libc::ENOTCONN => ErrorKind::NotConnected,
        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
        libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        libc::EADDRINUSE => ErrorKind::AddrInUse,
        libc::ENOENT => ErrorKind::NotFound,
        libc::EINTR => ErrorKind::Interrupted,
        libc::EINVAL => ErrorKind::InvalidInput,
        libc::ETIMEDOUT => ErrorKind::TimedOut,
        libc::EEXIST => ErrorKind::AlreadyExists,

        // These two constants can have the same value on some systems,
        // but different values on others, so we can't use a match
        // clause
        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => ErrorKind::WouldBlock,

        _ => ErrorKind::Other,
    }
}

#[doc(hidden)]
pub trait IsMinusOne {
    fn is_minus_one(&self) -> bool;
}

macro_rules! impl_is_minus_one {
    ($($t:ident)*) => ($(impl IsMinusOne for $t {
        fn is_minus_one(&self) -> bool {
            *self == -1
        }
    })*)
}

impl_is_minus_one! { i8 i16 i32 i64 isize }

pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
}

pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
    T: IsMinusOne,
    F: FnMut() -> T,
{
    loop {
        match cvt(f()) {
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            other => return other,
        }
    }
}

// On Unix-like platforms, libc::abort will unregister signal handlers
// including the SIGABRT handler, preventing the abort from being blocked, and
// fclose streams, with the side effect of flushing them so libc bufferred
// output will be printed.  Additionally the shell will generally print a more
// understandable error message like "Abort trap" rather than "Illegal
// instruction" that intrinsics::abort would cause, as intrinsics::abort is
// implemented as an illegal instruction.
pub unsafe fn abort_internal() -> ! {
    libc::abort()
}
<commit_msg>ignore signal SIGPIPE<commit_after>#![allow(dead_code)]
#![allow(missing_docs, nonstandard_style)]

use crate::io::ErrorKind;

pub use self::rand::hashmap_random_keys;
pub use crate::os::vxworks as platform;
pub use libc::strlen;

pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
pub mod thread_local;
pub mod time;

pub use crate::sys_common::os_str_bytes as os_str;

#[cfg(not(test))]
pub fn init() {
    // ignore SIGPIPE
    unsafe {
        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
    }
}

pub use libc::signal;

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as libc::c_int {
        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
        libc::ECONNRESET => ErrorKind::ConnectionReset,
        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
        libc::EPIPE => ErrorKind::BrokenPipe,
        libc::ENOTCONN => ErrorKind::NotConnected,
        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
        libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        libc::EADDRINUSE => ErrorKind::AddrInUse,
        libc::ENOENT => ErrorKind::NotFound,
        libc::EINTR => ErrorKind::Interrupted,
        libc::EINVAL => ErrorKind::InvalidInput,
        libc::ETIMEDOUT => ErrorKind::TimedOut,
        libc::EEXIST => ErrorKind::AlreadyExists,

        // These two constants can have the same value on some systems,
        // but different values on others, so we can't use a match
        // clause
        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => ErrorKind::WouldBlock,

        _ => ErrorKind::Other,
    }
}

#[doc(hidden)]
pub trait IsMinusOne {
    fn is_minus_one(&self) -> bool;
}

macro_rules! impl_is_minus_one {
    ($($t:ident)*) => ($(impl IsMinusOne for $t {
        fn is_minus_one(&self) -> bool {
            *self == -1
        }
    })*)
}

impl_is_minus_one! { i8 i16 i32 i64 isize }

pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
}

pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
    T: IsMinusOne,
    F: FnMut() -> T,
{
    loop {
        match cvt(f()) {
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            other => return other,
        }
    }
}

// On Unix-like platforms, libc::abort will unregister signal handlers
// including the SIGABRT handler, preventing the abort from being blocked, and
// fclose streams, with the side effect of flushing them so libc bufferred
// output will be printed.  Additionally the shell will generally print a more
// understandable error message like "Abort trap" rather than "Illegal
// instruction" that intrinsics::abort would cause, as intrinsics::abort is
// implemented as an illegal instruction.
pub unsafe fn abort_internal() -> ! {
    libc::abort()
}
<|endoftext|>


<commit_before>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use takeable_option::Takeable;
use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;
use glutin::{PossiblyCurrent as Pc, NotCurrent};

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new(
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<NotCurrent>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = cb.build_windowed(wb, events_loop)?;
        let gl_window = unsafe {
            gl_window.treat_as_current()
        };
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug(gl_window: glutin::WindowedContext<Pc>, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = Rc::new(RefCell::new(Takeable::new(gl_window)));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = try!(unsafe { context::Context::new(glutin_backend, checked, debug) });
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `WindowedContext` with the given window and context builders.
    ///
    /// This method ensures that the new `WindowedContext`'s `Context` will share the display lists of the
    /// original `WindowedContext`'s `Context`.
    pub fn rebuild(
        &self,
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<NotCurrent>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let cb = cb.with_shared_lists(gl_window.context());
            cb.build_windowed(wb, events_loop)?
        };
        let new_gl_window = unsafe {
            new_gl_window.treat_as_current()
        };

        // Replace the stored WindowedContext with the new one.
        let mut gl_window = self.gl_window.borrow_mut();
        Takeable::insert(&mut gl_window, new_gl_window);

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        try!(unsafe { self.context.rebuild(backend) });

        Ok(())
    }

    /// Borrow the inner glutin WindowedContext.
    #[inline]
    pub fn gl_window(&self) -> Ref<Takeable<glutin::WindowedContext<Pc>>> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize((w, h).into());
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

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

impl Error for DisplayCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => err.description(),
            DisplayCreationError::IncompatibleOpenGl(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("I/O Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::OsError(e)) => panic!("OS Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
		let gl_window_takeable = self.borrow();
        let gl_window = gl_window_takeable.window();
        let (width, height) = gl_window.get_inner_size()
            .map(|logical_size| logical_size.to_physical(gl_window.get_hidpi_factor()))
            .map(Into::into)
            // TODO: 800x600 ?
            .unwrap_or((800, 600));
        (width, height)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        let mut gl_window_takeable = self.borrow_mut();
        let gl_window = Takeable::take(&mut gl_window_takeable);
        let new_gl_window = gl_window.make_current().unwrap();
        Takeable::insert(&mut gl_window_takeable, new_gl_window);
    }
}
<commit_msg>Fix rebuilding<commit_after>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use takeable_option::Takeable;
use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;
use glutin::{PossiblyCurrent as Pc, NotCurrent};

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new(
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<NotCurrent>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = cb.build_windowed(wb, events_loop)?;
        let gl_window = unsafe {
            gl_window.treat_as_current()
        };
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug(gl_window: glutin::WindowedContext<Pc>, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = Rc::new(RefCell::new(Takeable::new(gl_window)));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = try!(unsafe { context::Context::new(glutin_backend, checked, debug) });
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `WindowedContext` with the given window and context builders.
    ///
    /// This method ensures that the new `WindowedContext`'s `Context` will share the display lists of the
    /// original `WindowedContext`'s `Context`.
    pub fn rebuild(
        &self,
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<NotCurrent>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let cb = cb.with_shared_lists(gl_window.context());
            cb.build_windowed(wb, events_loop)?
        };
        let new_gl_window = unsafe {
            new_gl_window.treat_as_current()
        };

        // Replace the stored WindowedContext with the new one.
        {
            let mut gl_window = self.gl_window.borrow_mut();
            Takeable::insert(&mut gl_window, new_gl_window);
        }

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        try!(unsafe { self.context.rebuild(backend) });

        Ok(())
    }

    /// Borrow the inner glutin WindowedContext.
    #[inline]
    pub fn gl_window(&self) -> Ref<Takeable<glutin::WindowedContext<Pc>>> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize((w, h).into());
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

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

impl Error for DisplayCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => err.description(),
            DisplayCreationError::IncompatibleOpenGl(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("I/O Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::OsError(e)) => panic!("OS Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
		let gl_window_takeable = self.borrow();
        let gl_window = gl_window_takeable.window();
        let (width, height) = gl_window.get_inner_size()
            .map(|logical_size| logical_size.to_physical(gl_window.get_hidpi_factor()))
            .map(Into::into)
            // TODO: 800x600 ?
            .unwrap_or((800, 600));
        (width, height)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        let mut gl_window_takeable = self.borrow_mut();
        let gl_window = Takeable::take(&mut gl_window_takeable);
        let new_gl_window = gl_window.make_current().unwrap();
        Takeable::insert(&mut gl_window_takeable, new_gl_window);
    }
}
<|endoftext|>


<commit_before>use super::Builder;
use std;

fn assert_build(input: &str) {
    let mut b = Builder::new(std::env::current_dir().unwrap());
    b.enable_validate_mode();
    b.eval_string(input).unwrap();
    if !b.assert_collector.success {
        assert!(false, b.assert_collector.failures);
    }
}

#[test]
fn test_comparisons() {
    assert_build(
        "
    let one = 1;
    let two = 2;
    let foo = \"foo\";
    let bar = \"bar\";
    let tpl1 = {
        foo = \"bar\",
        one = 1
    };
    let tpl2 = tpl1{};
    let tpl3 = {
        bar = \"foo\",
        two = 1
    };
    let list = [1, 2, 3];
    let list2 = list;
    let list3 = [1, 2];
    assert \"one == one\";
    assert \"one == one\";
    assert \"one >= one\";
    assert \"two > one\";
    assert \"two >= two\";
    assert \"tpl1 == tpl2\";
    assert \"tpl1 != tpl3\";
    assert \"list == list2\";
    assert \"list != list3\";
    ",
    );
}

#[test]
fn test_deep_comparison() {
    let input = "
    let tpl1 = {
        foo = \"bar\",
        lst = [1, 2, 3],
        inner = {
            fld = \"value\"
        }
    };
    let copy = tpl1;
    let extra = tpl1{one = 1};
    let less = {
        foo = \"bar\"
    };
    assert \"tpl1.inner == copy.inner\";
    assert \"tpl1.inner.fld == copy.inner.fld\";
    assert \"tpl1.lst == copy.lst\";
    assert \"tpl1.foo == copy.foo\";
    assert \"tpl1 == copy\";
    assert \"tpl1 != extra\";
    assert \"tpl1 != less\";
    ";
    assert_build(input);
}

#[test]
fn test_expression_comparisons() {
    assert_build("assert \"2 == 1+1\";");
    assert_build("assert \"(1+1) == 2\";");
    assert_build("assert \"(1+1) == (1+1)\";");
}

#[test]
fn test_binary_operator_precedence() {
    assert_build(
        "let result = 2 * 2 + 1;
    assert \"result == 5\";",
    );
    assert_build(
        "let result = 2 + 2 * 3;
    assert \"result == 8\";",
    );
    assert_build(
        "let result = 2 * (2 + 1);
    assert \"result == 6\";",
    );
}
<commit_msg>TESTS: Use EVAL as the file name for our compile test.<commit_after>use super::Builder;
use std;

fn assert_build(input: &str) {
    let mut b = Builder::new("<Eval>");
    b.enable_validate_mode();
    b.eval_string(input).unwrap();
    if !b.assert_collector.success {
        assert!(false, b.assert_collector.failures);
    }
}

#[test]
fn test_comparisons() {
    assert_build(
        "
    let one = 1;
    let two = 2;
    let foo = \"foo\";
    let bar = \"bar\";
    let tpl1 = {
        foo = \"bar\",
        one = 1
    };
    let tpl2 = tpl1{};
    let tpl3 = {
        bar = \"foo\",
        two = 1
    };
    let list = [1, 2, 3];
    let list2 = list;
    let list3 = [1, 2];
    assert \"one == one\";
    assert \"one == one\";
    assert \"one >= one\";
    assert \"two > one\";
    assert \"two >= two\";
    assert \"tpl1 == tpl2\";
    assert \"tpl1 != tpl3\";
    assert \"list == list2\";
    assert \"list != list3\";
    ",
    );
}

#[test]
fn test_deep_comparison() {
    let input = "
    let tpl1 = {
        foo = \"bar\",
        lst = [1, 2, 3],
        inner = {
            fld = \"value\"
        }
    };
    let copy = tpl1;
    let extra = tpl1{one = 1};
    let less = {
        foo = \"bar\"
    };
    assert \"tpl1.inner == copy.inner\";
    assert \"tpl1.inner.fld == copy.inner.fld\";
    assert \"tpl1.lst == copy.lst\";
    assert \"tpl1.foo == copy.foo\";
    assert \"tpl1 == copy\";
    assert \"tpl1 != extra\";
    assert \"tpl1 != less\";
    ";
    assert_build(input);
}

#[test]
fn test_expression_comparisons() {
    assert_build("assert \"2 == 1+1\";");
    assert_build("assert \"(1+1) == 2\";");
    assert_build("assert \"(1+1) == (1+1)\";");
}

#[test]
fn test_binary_operator_precedence() {
    assert_build(
        "let result = 2 * 2 + 1;
    assert \"result == 5\";",
    );
    assert_build(
        "let result = 2 + 2 * 3;
    assert \"result == 8\";",
    );
    assert_build(
        "let result = 2 * (2 + 1);
    assert \"result == 6\";",
    );
}
<|endoftext|>


<commit_before>use std::os;
use std::mem;
use std::fmt::Show;
use time;
use std::cell::RefCell;

thread_local!(static PROFILE_STACK: RefCell<Vec<u64>> = RefCell::new(Vec::new()));
thread_local!(static MESSAGES: RefCell<Vec<Message>> = RefCell::new(Vec::new()));

type Message = (uint, u64, String);

pub struct Profiler {
    desc: String,
}

fn enabled() -> bool { os::getenv("CARGO_PROFILE").is_some() }

pub fn start<T: Show>(desc: T) -> Profiler {
    if !enabled() { return Profiler { desc: String::new() } }

    PROFILE_STACK.with(|stack| stack.borrow_mut().push(time::precise_time_ns()));

    Profiler {
        desc: desc.to_string(),
    }
}

impl Drop for Profiler {
    fn drop(&mut self) {
        if !enabled() { return }

        let start = PROFILE_STACK.with(|stack| stack.borrow_mut().pop().unwrap());
        let end = time::precise_time_ns();

        let stack_len = PROFILE_STACK.with(|stack| stack.borrow().len());
        if stack_len == 0 {
            fn print(lvl: uint, msgs: &[Message]) {
                let mut last = 0;
                for (i, &(l, time, ref msg)) in msgs.iter().enumerate() {
                    if l != lvl { continue }

                    let mut spaces = String::new();
                    for _ in range(0u, lvl + 1) {
                        spaces.push_str("    ");
                    }

                    println!("{} {:6}ms - {}", spaces, time / 1000000, msg);

                    print(lvl + 1, msgs.slice(last, i));
                    last = i;
                }

            }
            MESSAGES.with(|msgs_rc| {
                let mut msgs = msgs_rc.borrow_mut();
                msgs.push((0, end - start, mem::replace(&mut self.desc, String::new())));
                print(0, msgs.as_slice());
            });
        } else {
            MESSAGES.with(|msgs| {
                let msg = mem::replace(&mut self.desc, String::new());
                msgs.borrow_mut().push((stack_len, end - start, msg));
            });
        }
    }
}
<commit_msg>Use std::iter repeat to generate indentation level<commit_after>use std::os;
use std::mem;
use std::fmt::Show;
use time;
use std::iter::repeat;
use std::cell::RefCell;

thread_local!(static PROFILE_STACK: RefCell<Vec<u64>> = RefCell::new(Vec::new()));
thread_local!(static MESSAGES: RefCell<Vec<Message>> = RefCell::new(Vec::new()));

type Message = (uint, u64, String);

pub struct Profiler {
    desc: String,
}

fn enabled() -> bool { os::getenv("CARGO_PROFILE").is_some() }

pub fn start<T: Show>(desc: T) -> Profiler {
    if !enabled() { return Profiler { desc: String::new() } }

    PROFILE_STACK.with(|stack| stack.borrow_mut().push(time::precise_time_ns()));

    Profiler {
        desc: desc.to_string(),
    }
}

impl Drop for Profiler {
    fn drop(&mut self) {
        if !enabled() { return }

        let start = PROFILE_STACK.with(|stack| stack.borrow_mut().pop().unwrap());
        let end = time::precise_time_ns();

        let stack_len = PROFILE_STACK.with(|stack| stack.borrow().len());
        if stack_len == 0 {
            fn print(lvl: uint, msgs: &[Message]) {
                let mut last = 0;
                for (i, &(l, time, ref msg)) in msgs.iter().enumerate() {
                    if l != lvl { continue }
                    println!("{} {:6}ms - {}", repeat("    ").take(lvl + 1).collect::<String>(),
                        time / 1000000, msg);

                    print(lvl + 1, msgs.slice(last, i));
                    last = i;
                }

            }
            MESSAGES.with(|msgs_rc| {
                let mut msgs = msgs_rc.borrow_mut();
                msgs.push((0, end - start, mem::replace(&mut self.desc, String::new())));
                print(0, msgs.as_slice());
            });
        } else {
            MESSAGES.with(|msgs| {
                let msg = mem::replace(&mut self.desc, String::new());
                msgs.borrow_mut().push((stack_len, end - start, msg));
            });
        }
    }
}
<|endoftext|>