<commit_before>
use spirv_utils::{self, desc, instruction};
use core;
use core::shade::{self, BaseType, ContainerType, TextureType};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Variable {
    id: desc::Id,
    name: String,
    ty: desc::Id,
    storage_class: desc::StorageClass,
    decoration: Vec<instruction::Decoration>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct EntryPoint {
    name: String,
    stage: shade::Stage,
    interface: Box<[desc::Id]>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Ty {
    Basic(BaseType, ContainerType),
    Image(BaseType, TextureType),
    Struct(Vec<Type>),
    Sampler,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Type {
    id: desc::Id,
    ty: Ty,
    decoration: Vec<instruction::Decoration>,
}

fn map_execution_model_to_stage(model: desc::ExecutionModel) -> Option<shade::Stage> {
    use spirv_utils::desc::ExecutionModel::*;
    match model {
        Vertex => Some(shade::Stage::Vertex),
        Geometry => Some(shade::Stage::Geometry),
        Fragment => Some(shade::Stage::Pixel),

        _ => None,
    }
}

fn map_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Name { ref name, .. } => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_member_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberName { ref name, member, .. } if member == member_id => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Decorate { ref decoration, .. } => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_member_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberDecorate { ref decoration, member, .. } if member == member_id => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_image_to_texture_type(dim: desc::Dim, arrayed: bool, multisampled: bool) -> TextureType {
    use spirv_utils::desc::Dim;
    let arrayed = if arrayed { shade::IsArray::Array } else { shade::IsArray::NoArray };
    let multisampled = if multisampled { shade::IsMultiSample::MultiSample } else { shade::IsMultiSample::NoMultiSample };
    match dim {
        Dim::_1D => shade::TextureType::D1(arrayed),
        Dim::_2D => shade::TextureType::D2(arrayed, multisampled),
        Dim::_3D => shade::TextureType::D3,
        Dim::Cube => shade::TextureType::Cube(arrayed),
        Dim::Buffer => shade::TextureType::Buffer,

        _ => unimplemented!(),
    }
}

fn map_scalar_to_basetype(instr: &instruction::Instruction) -> Option<BaseType> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { .. } => Some(BaseType::Bool),
        Instruction::TypeInt { width: 32, signed: false, .. } => Some(BaseType::U32),
        Instruction::TypeInt { width: 32, signed: true, .. } => Some(BaseType::I32),
        Instruction::TypeFloat { width: 32, ..} => Some(BaseType::F32),
        Instruction::TypeFloat { width: 64, ..} => Some(BaseType::F64),

        _ => None,
    }
}

fn map_instruction_to_type(module: &spirv_utils::RawModule, instr: &instruction::Instruction) -> Option<Type> {
    use spirv_utils::instruction::{Decoration, Instruction};
    let id_ty = match *instr {
        Instruction::TypeBool { result_type } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: false } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: true } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 32 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 64 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeVector { result_type, type_id, len } => {
            let comp_ty = module.def(type_id).unwrap();
            Some((result_type, Ty::Basic(map_scalar_to_basetype(comp_ty).unwrap(), ContainerType::Vector(len as u8))))
        },
        Instruction::TypeMatrix { result_type, type_id, cols } => {
            let (base, rows) = match *module.def(type_id).unwrap() {
                Instruction::TypeVector { type_id, len, .. } => {
                    let comp_ty = module.def(type_id).unwrap();
                    (map_scalar_to_basetype(comp_ty).unwrap(), len)
                },
                _ => unreachable!(), // SPIR-V module would be invalid
            };

            let decoration = map_decorations_by_id(&module, result_type.into());

            // NOTE: temporary value, changes might be needed later depending on the decorations of the variable
            let matrix_format = if decoration.iter().find(|deco| **deco == Decoration::RowMajor).is_some() {
                shade::MatrixFormat::RowMajor
            } else {
                shade::MatrixFormat::ColumnMajor
            };

            Some((result_type, Ty::Basic(base, ContainerType::Matrix(matrix_format, rows as u8, cols as u8))))
        },
        Instruction::TypeStruct { result_type, ref fields } => {
            Some((
                result_type,
                Ty::Struct(
                    fields.iter().filter_map(|field| // TODO: should be `map()`, currently to ignore unsupported types
                        map_instruction_to_type(module, module.def(*field).unwrap())
                    ).collect::<Vec<_>>()
                )
            ))
        },
        Instruction::TypeSampler { result_type } => {
            Some((result_type, Ty::Sampler))
        },
        Instruction::TypeImage { result_type, type_id, dim, arrayed, multisampled, .. } => {
            Some((result_type, Ty::Image(map_scalar_to_basetype(module.def(type_id).unwrap()).unwrap(), map_image_to_texture_type(dim, arrayed, multisampled))))
        },

        _ => None,
    };

    id_ty.map(|(id, ty)| Type {
            id: id.into(),
            ty: ty,
            decoration: map_decorations_by_id(&module, id.into()),
        })
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SpirvReflection {
    entry_points: Vec<EntryPoint>,
    variables: Vec<Variable>,
    types: Vec<Type>,
}

pub fn reflect_spirv_module(code: &[u8]) -> SpirvReflection {
    use spirv_utils::instruction::Instruction;

    let module = spirv_utils::RawModule::read_module(code).unwrap();

    let mut entry_points = Vec::new();
    let mut variables = Vec::new();
    let mut types = Vec::new();
    for instr in module.instructions() {
        match *instr {
            Instruction::EntryPoint { execution_model, ref name, ref interface, .. } => {
                if let Some(stage) = map_execution_model_to_stage(execution_model) {
                    entry_points.push(EntryPoint {
                        name: name.clone(),
                        stage: stage,
                        interface: interface.clone(),
                    });
                } else {
                    error!("Unsupported execution model: {:?}", execution_model);
                }
            },
            Instruction::Variable { result_type, result_id, storage_class, .. } => {
                let decoration = map_decorations_by_id(&module, result_id.into());
                let ty = {
                    // remove indirection layer as the type of every variable is a OpTypePointer
                    let ptr_ty = module.def::<desc::TypeId>(result_type.into()).unwrap();
                    match *ptr_ty {
                        Instruction::TypePointer { ref pointee, .. } => *pointee,
                        _ => unreachable!(), // SPIR-V module would be invalid
                    }
                };

                // Every variable MUST have an name annotation
                // `glslang` seems to emit empty strings for uniforms with struct type,
                // therefore we need to retrieve the name from the struct decl
                let name = {
                    let name = map_name_by_id(&module, result_id.into()).unwrap();
                    if name.is_empty() {
                        map_name_by_id(&module, ty.into()).unwrap()
                    } else {
                        name
                    }
                };

                variables.push(Variable {
                    id: result_id.into(),
                    name: name.into(),
                    ty: ty.into(),
                    storage_class: storage_class,
                    decoration: decoration,
                });
            },

            _ => {
                // Reflect types, if we have OpTypeXXX
                if let Some(ty) = map_instruction_to_type(&module, instr) {
                    types.push(ty);
                }
            },
        }
    }

    SpirvReflection {
        entry_points: entry_points,
        variables: variables,
        types: types,
    }
}

pub fn populate_info(info: &mut shade::ProgramInfo, stage: shade::Stage, reflection: &SpirvReflection) {
    if stage == shade::Stage::Vertex {
        // record vertex attributes
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for attrib in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *attrib) {
                    if var.storage_class == desc::StorageClass::Input {
                        let attrib_name = var.name.clone();
                        let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                        instruction::Decoration::Location(slot) => Some(slot),
                                        _ => None,
                                    }).next().expect("Missing location decoration");

                        let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                        if let Ty::Basic(base, container) = ty.ty {
                            info.vertex_attributes.push(shade::AttributeVar {
                                name: attrib_name,
                                slot: slot as core::AttributeSlot,
                                base_type: base,
                                container: container,
                            });
                        } else {
                            error!("Unsupported type as vertex attribute: {:?}", ty.ty);
                        }
                    }
                } else {
                    error!("Missing vertex attribute reflection: {:?}", attrib);
                }
            }
        }
    } else if stage == shade::Stage::Pixel {
        // record pixel outputs
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for out in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *out) {
                    if var.storage_class == desc::StorageClass::Output {
                        let target_name = var.name.clone();
                        let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                        instruction::Decoration::Location(slot) => Some(slot),
                                        _ => None,
                                    }).next().expect("Missing location decoration");

                        let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                        if let Ty::Basic(base, container) = ty.ty {
                            info.outputs.push(shade::OutputVar {
                                name: target_name,
                                slot: slot as core::ColorSlot,
                                base_type: base,
                                container: container,
                            });
                        } else {
                            error!("Unsupported type as pixel shader output: {:?}", ty.ty);
                        }
                    }
                } else {
                    error!("Missing pixel shader output reflection: {:?}", out);
                }
            }
        }
    }

    // Handle resources
    // We use only one descriptor set currently
    for var in reflection.variables.iter() {
        use spirv_utils::desc::StorageClass::*;
        match var.storage_class {
            Uniform | UniformConstant => {
                if let Some(ty) = reflection.types.iter().find(|ty| ty.id == var.ty) {
                    // constant buffers
                    match ty.ty {
                        Ty::Struct(ref fields) => {
                            let mut elements = Vec::new();
                            for field in fields {
                                // TODO:
                            }

                            let buffer_name = var.name.clone();
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.constant_buffers.push(shade::ConstantBufferVar {
                                name: buffer_name,
                                slot: slot as core::ConstantBufferSlot,
                                size: 0, // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                                elements: elements,
                            });
                        },

                        Ty::Sampler => {
                            let sampler_name = var.name.trim_right_matches('_');
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.samplers.push(shade::SamplerVar {
                                name: sampler_name.to_owned(),
                                slot: slot as core::SamplerSlot,
                                ty: shade::SamplerType(shade::IsComparison::NoCompare, shade::IsRect::NoRect), // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        Ty::Image(base_type, texture_type) => {
                            let texture_name = var.name.clone();
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.textures.push(shade::TextureVar {
                                name: texture_name,
                                slot: slot as core::ResourceViewSlot,
                                base_type: base_type,
                                ty: texture_type,
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        _ => (),
                    }
                } else {
                    error!("Unsupported uniform type: {:?}", var.ty);
                }
            },
            _ => (),
        }
    }
}
<commit_msg>Vulkan: Better error handling for missing entry points<commit_after>
use spirv_utils::{self, desc, instruction};
use core;
use core::shade::{self, BaseType, ContainerType, TextureType};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Variable {
    id: desc::Id,
    name: String,
    ty: desc::Id,
    storage_class: desc::StorageClass,
    decoration: Vec<instruction::Decoration>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct EntryPoint {
    name: String,
    stage: shade::Stage,
    interface: Box<[desc::Id]>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Ty {
    Basic(BaseType, ContainerType),
    Image(BaseType, TextureType),
    Struct(Vec<Type>),
    Sampler,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Type {
    id: desc::Id,
    ty: Ty,
    decoration: Vec<instruction::Decoration>,
}

fn map_execution_model_to_stage(model: desc::ExecutionModel) -> Option<shade::Stage> {
    use spirv_utils::desc::ExecutionModel::*;
    match model {
        Vertex => Some(shade::Stage::Vertex),
        Geometry => Some(shade::Stage::Geometry),
        Fragment => Some(shade::Stage::Pixel),

        _ => None,
    }
}

fn map_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Name { ref name, .. } => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_member_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberName { ref name, member, .. } if member == member_id => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Decorate { ref decoration, .. } => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_member_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberDecorate { ref decoration, member, .. } if member == member_id => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_image_to_texture_type(dim: desc::Dim, arrayed: bool, multisampled: bool) -> TextureType {
    use spirv_utils::desc::Dim;
    let arrayed = if arrayed { shade::IsArray::Array } else { shade::IsArray::NoArray };
    let multisampled = if multisampled { shade::IsMultiSample::MultiSample } else { shade::IsMultiSample::NoMultiSample };
    match dim {
        Dim::_1D => shade::TextureType::D1(arrayed),
        Dim::_2D => shade::TextureType::D2(arrayed, multisampled),
        Dim::_3D => shade::TextureType::D3,
        Dim::Cube => shade::TextureType::Cube(arrayed),
        Dim::Buffer => shade::TextureType::Buffer,

        _ => unimplemented!(),
    }
}

fn map_scalar_to_basetype(instr: &instruction::Instruction) -> Option<BaseType> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { .. } => Some(BaseType::Bool),
        Instruction::TypeInt { width: 32, signed: false, .. } => Some(BaseType::U32),
        Instruction::TypeInt { width: 32, signed: true, .. } => Some(BaseType::I32),
        Instruction::TypeFloat { width: 32, ..} => Some(BaseType::F32),
        Instruction::TypeFloat { width: 64, ..} => Some(BaseType::F64),

        _ => None,
    }
}

fn map_instruction_to_type(module: &spirv_utils::RawModule, instr: &instruction::Instruction) -> Option<Type> {
    use spirv_utils::instruction::{Decoration, Instruction};
    let id_ty = match *instr {
        Instruction::TypeBool { result_type } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: false } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: true } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 32 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 64 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeVector { result_type, type_id, len } => {
            let comp_ty = module.def(type_id).unwrap();
            Some((result_type, Ty::Basic(map_scalar_to_basetype(comp_ty).unwrap(), ContainerType::Vector(len as u8))))
        },
        Instruction::TypeMatrix { result_type, type_id, cols } => {
            let (base, rows) = match *module.def(type_id).unwrap() {
                Instruction::TypeVector { type_id, len, .. } => {
                    let comp_ty = module.def(type_id).unwrap();
                    (map_scalar_to_basetype(comp_ty).unwrap(), len)
                },
                _ => unreachable!(), // SPIR-V module would be invalid
            };

            let decoration = map_decorations_by_id(&module, result_type.into());

            // NOTE: temporary value, changes might be needed later depending on the decorations of the variable
            let matrix_format = if decoration.iter().find(|deco| **deco == Decoration::RowMajor).is_some() {
                shade::MatrixFormat::RowMajor
            } else {
                shade::MatrixFormat::ColumnMajor
            };

            Some((result_type, Ty::Basic(base, ContainerType::Matrix(matrix_format, rows as u8, cols as u8))))
        },
        Instruction::TypeStruct { result_type, ref fields } => {
            Some((
                result_type,
                Ty::Struct(
                    fields.iter().filter_map(|field| // TODO: should be `map()`, currently to ignore unsupported types
                        map_instruction_to_type(module, module.def(*field).unwrap())
                    ).collect::<Vec<_>>()
                )
            ))
        },
        Instruction::TypeSampler { result_type } => {
            Some((result_type, Ty::Sampler))
        },
        Instruction::TypeImage { result_type, type_id, dim, arrayed, multisampled, .. } => {
            Some((result_type, Ty::Image(map_scalar_to_basetype(module.def(type_id).unwrap()).unwrap(), map_image_to_texture_type(dim, arrayed, multisampled))))
        },

        _ => None,
    };

    id_ty.map(|(id, ty)| Type {
            id: id.into(),
            ty: ty,
            decoration: map_decorations_by_id(&module, id.into()),
        })
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SpirvReflection {
    entry_points: Vec<EntryPoint>,
    variables: Vec<Variable>,
    types: Vec<Type>,
}

pub fn reflect_spirv_module(code: &[u8]) -> SpirvReflection {
    use spirv_utils::instruction::Instruction;

    let module = spirv_utils::RawModule::read_module(code).unwrap();

    let mut entry_points = Vec::new();
    let mut variables = Vec::new();
    let mut types = Vec::new();
    for instr in module.instructions() {
        match *instr {
            Instruction::EntryPoint { execution_model, ref name, ref interface, .. } => {
                if let Some(stage) = map_execution_model_to_stage(execution_model) {
                    entry_points.push(EntryPoint {
                        name: name.clone(),
                        stage: stage,
                        interface: interface.clone(),
                    });
                } else {
                    error!("Unsupported execution model: {:?}", execution_model);
                }
            },
            Instruction::Variable { result_type, result_id, storage_class, .. } => {
                let decoration = map_decorations_by_id(&module, result_id.into());
                let ty = {
                    // remove indirection layer as the type of every variable is a OpTypePointer
                    let ptr_ty = module.def::<desc::TypeId>(result_type.into()).unwrap();
                    match *ptr_ty {
                        Instruction::TypePointer { ref pointee, .. } => *pointee,
                        _ => unreachable!(), // SPIR-V module would be invalid
                    }
                };

                // Every variable MUST have an name annotation
                // `glslang` seems to emit empty strings for uniforms with struct type,
                // therefore we need to retrieve the name from the struct decl
                let name = {
                    let name = map_name_by_id(&module, result_id.into()).unwrap();
                    if name.is_empty() {
                        map_name_by_id(&module, ty.into()).unwrap()
                    } else {
                        name
                    }
                };

                variables.push(Variable {
                    id: result_id.into(),
                    name: name.into(),
                    ty: ty.into(),
                    storage_class: storage_class,
                    decoration: decoration,
                });
            },

            _ => {
                // Reflect types, if we have OpTypeXXX
                if let Some(ty) = map_instruction_to_type(&module, instr) {
                    types.push(ty);
                }
            },
        }
    }

    SpirvReflection {
        entry_points: entry_points,
        variables: variables,
        types: types,
    }
}

pub fn populate_info(info: &mut shade::ProgramInfo, stage: shade::Stage, reflection: &SpirvReflection) {
    if stage == shade::Stage::Vertex {
        // record vertex attributes
        let entry_point = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage).expect("Couln't find entry point!");
        for attrib in entry_point.interface.iter() {
            if let Some(var) = reflection.variables.iter().find(|var| var.id == *attrib) {
                if var.storage_class == desc::StorageClass::Input {
                    let attrib_name = var.name.clone();
                    let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                    instruction::Decoration::Location(slot) => Some(slot),
                                    _ => None,
                                }).next().expect("Missing location decoration");

                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.vertex_attributes.push(shade::AttributeVar {
                            name: attrib_name,
                            slot: slot as core::AttributeSlot,
                            base_type: base,
                            container: container,
                        });
                    } else {
                        error!("Unsupported type as vertex attribute: {:?}", ty.ty);
                    }
                }
            } else {
                error!("Missing vertex attribute reflection: {:?}", attrib);
            }
        }
    } else if stage == shade::Stage::Pixel {
        // record pixel outputs
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for out in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *out) {
                    if var.storage_class == desc::StorageClass::Output {
                        let target_name = var.name.clone();
                        let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                        instruction::Decoration::Location(slot) => Some(slot),
                                        _ => None,
                                    }).next().expect("Missing location decoration");

                        let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                        if let Ty::Basic(base, container) = ty.ty {
                            info.outputs.push(shade::OutputVar {
                                name: target_name,
                                slot: slot as core::ColorSlot,
                                base_type: base,
                                container: container,
                            });
                        } else {
                            error!("Unsupported type as pixel shader output: {:?}", ty.ty);
                        }
                    }
                } else {
                    error!("Missing pixel shader output reflection: {:?}", out);
                }
            }
        }
    }

    // Handle resources
    // We use only one descriptor set currently
    for var in reflection.variables.iter() {
        use spirv_utils::desc::StorageClass::*;
        match var.storage_class {
            Uniform | UniformConstant => {
                if let Some(ty) = reflection.types.iter().find(|ty| ty.id == var.ty) {
                    // constant buffers
                    match ty.ty {
                        Ty::Struct(ref fields) => {
                            let mut elements = Vec::new();
                            for field in fields {
                                // TODO:
                            }

                            let buffer_name = var.name.clone();
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.constant_buffers.push(shade::ConstantBufferVar {
                                name: buffer_name,
                                slot: slot as core::ConstantBufferSlot,
                                size: 0, // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                                elements: elements,
                            });
                        },

                        Ty::Sampler => {
                            let sampler_name = var.name.trim_right_matches('_');
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.samplers.push(shade::SamplerVar {
                                name: sampler_name.to_owned(),
                                slot: slot as core::SamplerSlot,
                                ty: shade::SamplerType(shade::IsComparison::NoCompare, shade::IsRect::NoRect), // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        Ty::Image(base_type, texture_type) => {
                            let texture_name = var.name.clone();
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.textures.push(shade::TextureVar {
                                name: texture_name,
                                slot: slot as core::ResourceViewSlot,
                                base_type: base_type,
                                ty: texture_type,
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        _ => (),
                    }
                } else {
                    error!("Unsupported uniform type: {:?}", var.ty);
                }
            },
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Slightly cleaner form argument parsing.<commit_after><|endoftext|>


<commit_before><commit_msg>Forgot to include raptor_object.rs<commit_after>#![allow(non_camel_case_types)]
#![allow(dead_code)]

#[derive(Debug)]
pub enum RaptorType {
    NULL,
    INT,
    BOOL,
    FLOAT,
    USER_TYPE{id: u32}
}

#[derive(Debug)]
pub enum RaptorKind {
    VECTOR,
    OBJECT,
}

#[derive(Debug)]
pub struct RaptorObject {
    r_type: RaptorType,
    r_kind: RaptorKind,
    data: Vec<u32>,
}

impl RaptorObject {
    pub fn new() -> RaptorObject {
        RaptorObject {
            r_type: RaptorType::NULL,
            r_kind: RaptorKind::OBJECT,
            data: Vec::with_capacity(0),
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>style: Fix serialization of @namespace rule.<commit_after><|endoftext|>


<commit_before>// Copyright 2012-2014 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.

//! The arena, a fast but limited type of allocator.
//!
//! Arenas are a type of allocator that destroy the objects within, all at
//! once, once the arena itself is destroyed. They do not support deallocation
//! of individual objects while the arena itself is still alive. The benefit
//! of an arena is very fast allocation; just a pointer bump.
//!
//! This crate implements `TypedArena`, a simple arena that can only hold
//! objects of a single type.

#![crate_name = "arena"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       test(no_crate_inject, attr(deny(warnings))))]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(alloc)]
#![feature(core_intrinsics)]
#![feature(heap_api)]
#![feature(heap_api)]
#![feature(staged_api)]
#![feature(dropck_parametricity)]
#![cfg_attr(test, feature(test))]

#![allow(deprecated)]

extern crate alloc;

use std::cell::{Cell, RefCell};
use std::cmp;
use std::intrinsics;
use std::marker::{PhantomData, Send};
use std::mem;
use std::ptr;

use alloc::heap;
use alloc::raw_vec::RawVec;

/// An arena that can hold objects of only one type.
pub struct TypedArena<T> {
    /// The capacity of the first chunk (once it is allocated).
    first_chunk_capacity: usize,

    /// A pointer to the next object to be allocated.
    ptr: Cell<*mut T>,

    /// A pointer to the end of the allocated area. When this pointer is
    /// reached, a new chunk is allocated.
    end: Cell<*mut T>,

    /// A vector of arena chunks.
    chunks: RefCell<Vec<TypedArenaChunk<T>>>,

    /// Marker indicating that dropping the arena causes its owned
    /// instances of `T` to be dropped.
    _own: PhantomData<T>,
}

struct TypedArenaChunk<T> {
    /// The raw storage for the arena chunk.
    storage: RawVec<T>,
}

impl<T> TypedArenaChunk<T> {
    #[inline]
    unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
        TypedArenaChunk { storage: RawVec::with_capacity(capacity) }
    }

    /// Destroys this arena chunk.
    #[inline]
    unsafe fn destroy(&mut self, len: usize) {
        // The branch on needs_drop() is an -O1 performance optimization.
        // Without the branch, dropping TypedArena<u8> takes linear time.
        if intrinsics::needs_drop::<T>() {
            let mut start = self.start();
            // Destroy all allocated objects.
            for _ in 0..len {
                ptr::drop_in_place(start);
                start = start.offset(1);
            }
        }
    }

    // Returns a pointer to the first allocated object.
    #[inline]
    fn start(&self) -> *mut T {
        self.storage.ptr()
    }

    // Returns a pointer to the end of the allocated space.
    #[inline]
    fn end(&self) -> *mut T {
        unsafe {
            if mem::size_of::<T>() == 0 {
                // A pointer as large as possible for zero-sized elements.
                !0 as *mut T
            } else {
                self.start().offset(self.storage.cap() as isize)
            }
        }
    }
}

const PAGE: usize = 4096;

impl<T> TypedArena<T> {
    /// Creates a new `TypedArena`.
    #[inline]
    pub fn new() -> TypedArena<T> {
        // Reserve at least one page.
        let elem_size = cmp::max(1, mem::size_of::<T>());
        TypedArena::with_capacity(PAGE / elem_size)
    }

    /// Creates a new `TypedArena`. Each chunk used within the arena will have
    /// space for at least the given number of objects.
    #[inline]
    pub fn with_capacity(capacity: usize) -> TypedArena<T> {
        TypedArena {
            first_chunk_capacity: cmp::max(1, capacity),
            // We set both `ptr` and `end` to 0 so that the first call to
            // alloc() will trigger a grow().
            ptr: Cell::new(0 as *mut T),
            end: Cell::new(0 as *mut T),
            chunks: RefCell::new(vec![]),
            _own: PhantomData,
        }
    }

    /// Allocates an object in the `TypedArena`, returning a reference to it.
    #[inline]
    pub fn alloc(&self, object: T) -> &mut T {
        if self.ptr == self.end {
            self.grow()
        }

        unsafe {
            if mem::size_of::<T>() == 0 {
                self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
                let ptr = heap::EMPTY as *mut T;
                // Don't drop the object. This `write` is equivalent to `forget`.
                ptr::write(ptr, object);
                &mut *ptr
            } else {
                let ptr = self.ptr.get();
                // Advance the pointer.
                self.ptr.set(self.ptr.get().offset(1));
                // Write into uninitialized memory.
                ptr::write(ptr, object);
                &mut *ptr
            }
        }
    }

    /// Grows the arena.
    #[inline(never)]
    #[cold]
    fn grow(&self) {
        unsafe {
            let mut chunks = self.chunks.borrow_mut();
            let (chunk, new_capacity);
            if let Some(last_chunk) = chunks.last_mut() {
                if last_chunk.storage.double_in_place() {
                    self.end.set(last_chunk.end());
                    return;
                } else {
                    let prev_capacity = last_chunk.storage.cap();
                    new_capacity = prev_capacity.checked_mul(2).unwrap();
                }
            } else {
                new_capacity = self.first_chunk_capacity;
            }
            chunk = TypedArenaChunk::<T>::new(new_capacity);
            self.ptr.set(chunk.start());
            self.end.set(chunk.end());
            chunks.push(chunk);
        }
    }
    /// Clears the arena. Deallocates all but the longest chunk which may be reused.
    pub fn clear(&mut self) {
        unsafe {
            // Clear the last chunk, which is partially filled.
            let mut chunks_borrow = self.chunks.borrow_mut();
            if let Some(mut last_chunk) = chunks_borrow.pop() {
                self.clear_last_chunk(&mut last_chunk);
                // If `T` is ZST, code below has no effect.
                for mut chunk in chunks_borrow.drain(..) {
                    let cap = chunk.storage.cap();
                    chunk.destroy(cap);
                }
                chunks_borrow.push(last_chunk);
            }
        }
    }

    // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
    // chunks.
    fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
        // Determine how much was filled.
        let start = last_chunk.start() as usize;
        // We obtain the value of the pointer to the first uninitialized element.
        let end = self.ptr.get() as usize;
        // We then calculate the number of elements to be dropped in the last chunk,
        // which is the filled area's length.
        let diff = if mem::size_of::<T>() == 0 {
            // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
            // the number of zero-sized values in the last and only chunk, just out of caution.
            // Recall that `end` was incremented for each allocated value.
            end - start
        } else {
            (end - start) / mem::size_of::<T>()
        };
        // Pass that to the `destroy` method.
        unsafe {
            last_chunk.destroy(diff);
        }
        // Reset the chunk.
        self.ptr.set(last_chunk.start());
    }
}

impl<T> Drop for TypedArena<T> {
    #[unsafe_destructor_blind_to_params]
    fn drop(&mut self) {
        unsafe {
            // Determine how much was filled.
            let mut chunks_borrow = self.chunks.borrow_mut();
            if let Some(mut last_chunk) = chunks_borrow.pop() {
                // Drop the contents of the last chunk.
                self.clear_last_chunk(&mut last_chunk);
                // The last chunk will be dropped. Destroy all other chunks.
                for chunk in chunks_borrow.iter_mut() {
                    let cap = chunk.storage.cap();
                    chunk.destroy(cap);
                }
            }
            // RawVec handles deallocation of `last_chunk` and `self.chunks`.
        }
    }
}

unsafe impl<T: Send> Send for TypedArena<T> {}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use super::TypedArena;
    use std::cell::Cell;

    #[allow(dead_code)]
    #[derive(Debug, Eq, PartialEq)]
    struct Point {
        x: i32,
        y: i32,
        z: i32,
    }

    #[test]
    pub fn test_unused() {
        let arena: TypedArena<Point> = TypedArena::new();
        assert!(arena.chunks.borrow().is_empty());
    }

    #[test]
    fn test_arena_alloc_nested() {
        struct Inner {
            value: u8,
        }
        struct Outer<'a> {
            inner: &'a Inner,
        }
        enum EI<'e> {
            I(Inner),
            O(Outer<'e>),
        }

        struct Wrap<'a>(TypedArena<EI<'a>>);

        impl<'a> Wrap<'a> {
            fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
                let r: &EI = self.0.alloc(EI::I(f()));
                if let &EI::I(ref i) = r {
                    i
                } else {
                    panic!("mismatch");
                }
            }
            fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
                let r: &EI = self.0.alloc(EI::O(f()));
                if let &EI::O(ref o) = r {
                    o
                } else {
                    panic!("mismatch");
                }
            }
        }

        let arena = Wrap(TypedArena::new());

        let result = arena.alloc_outer(|| {
            Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }
        });

        assert_eq!(result.inner.value, 10);
    }

    #[test]
    pub fn test_copy() {
        let arena = TypedArena::new();
        for _ in 0..100000 {
            arena.alloc(Point { x: 1, y: 2, z: 3 });
        }
    }

    #[bench]
    pub fn bench_copy(b: &mut Bencher) {
        let arena = TypedArena::new();
        b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 }))
    }

    #[bench]
    pub fn bench_copy_nonarena(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 });
        })
    }

    #[allow(dead_code)]
    struct Noncopy {
        string: String,
        array: Vec<i32>,
    }

    #[test]
    pub fn test_noncopy() {
        let arena = TypedArena::new();
        for _ in 0..100000 {
            arena.alloc(Noncopy {
                string: "hello world".to_string(),
                array: vec![1, 2, 3, 4, 5],
            });
        }
    }

    #[test]
    pub fn test_typed_arena_zero_sized() {
        let arena = TypedArena::new();
        for _ in 0..100000 {
            arena.alloc(());
        }
    }

    #[test]
    pub fn test_typed_arena_clear() {
        let mut arena = TypedArena::new();
        for _ in 0..10 {
            arena.clear();
            for _ in 0..10000 {
                arena.alloc(Point { x: 1, y: 2, z: 3 });
            }
        }
    }

    // Drop tests

    struct DropCounter<'a> {
        count: &'a Cell<u32>,
    }

    impl<'a> Drop for DropCounter<'a> {
        fn drop(&mut self) {
            self.count.set(self.count.get() + 1);
        }
    }

    #[test]
    fn test_typed_arena_drop_count() {
        let counter = Cell::new(0);
        {
            let arena: TypedArena<DropCounter> = TypedArena::new();
            for _ in 0..100 {
                // Allocate something with drop glue to make sure it doesn't leak.
                arena.alloc(DropCounter { count: &counter });
            }
        };
        assert_eq!(counter.get(), 100);
    }

    #[test]
    fn test_typed_arena_drop_on_clear() {
        let counter = Cell::new(0);
        let mut arena: TypedArena<DropCounter> = TypedArena::new();
        for i in 0..10 {
            for _ in 0..100 {
                // Allocate something with drop glue to make sure it doesn't leak.
                arena.alloc(DropCounter { count: &counter });
            }
            arena.clear();
            assert_eq!(counter.get(), i * 100 + 100);
        }
    }

    thread_local! {
        static DROP_COUNTER: Cell<u32> = Cell::new(0)
    }

    struct SmallDroppable;

    impl Drop for SmallDroppable {
        fn drop(&mut self) {
            DROP_COUNTER.with(|c| c.set(c.get() + 1));
        }
    }

    #[test]
    fn test_typed_arena_drop_small_count() {
        DROP_COUNTER.with(|c| c.set(0));
        {
            let arena: TypedArena<SmallDroppable> = TypedArena::new();
            for _ in 0..100 {
                // Allocate something with drop glue to make sure it doesn't leak.
                arena.alloc(SmallDroppable);
            }
            // dropping
        };
        assert_eq!(DROP_COUNTER.with(|c| c.get()), 100);
    }

    #[bench]
    pub fn bench_noncopy(b: &mut Bencher) {
        let arena = TypedArena::new();
        b.iter(|| {
            arena.alloc(Noncopy {
                string: "hello world".to_string(),
                array: vec![1, 2, 3, 4, 5],
            })
        })
    }

    #[bench]
    pub fn bench_noncopy_nonarena(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = Box::new(Noncopy {
                string: "hello world".to_string(),
                array: vec![1, 2, 3, 4, 5],
            });
        })
    }
}
<commit_msg>[breaking-change] Remove TypedArena::with_capacity.<commit_after>// Copyright 2012-2014 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.

//! The arena, a fast but limited type of allocator.
//!
//! Arenas are a type of allocator that destroy the objects within, all at
//! once, once the arena itself is destroyed. They do not support deallocation
//! of individual objects while the arena itself is still alive. The benefit
//! of an arena is very fast allocation; just a pointer bump.
//!
//! This crate implements `TypedArena`, a simple arena that can only hold
//! objects of a single type.

#![crate_name = "arena"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       test(no_crate_inject, attr(deny(warnings))))]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(alloc)]
#![feature(core_intrinsics)]
#![feature(heap_api)]
#![feature(heap_api)]
#![feature(staged_api)]
#![feature(dropck_parametricity)]
#![cfg_attr(test, feature(test))]

#![allow(deprecated)]

extern crate alloc;

use std::cell::{Cell, RefCell};
use std::cmp;
use std::intrinsics;
use std::marker::{PhantomData, Send};
use std::mem;
use std::ptr;

use alloc::heap;
use alloc::raw_vec::RawVec;

/// An arena that can hold objects of only one type.
pub struct TypedArena<T> {
    /// A pointer to the next object to be allocated.
    ptr: Cell<*mut T>,

    /// A pointer to the end of the allocated area. When this pointer is
    /// reached, a new chunk is allocated.
    end: Cell<*mut T>,

    /// A vector of arena chunks.
    chunks: RefCell<Vec<TypedArenaChunk<T>>>,

    /// Marker indicating that dropping the arena causes its owned
    /// instances of `T` to be dropped.
    _own: PhantomData<T>,
}

struct TypedArenaChunk<T> {
    /// The raw storage for the arena chunk.
    storage: RawVec<T>,
}

impl<T> TypedArenaChunk<T> {
    #[inline]
    unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
        TypedArenaChunk { storage: RawVec::with_capacity(capacity) }
    }

    /// Destroys this arena chunk.
    #[inline]
    unsafe fn destroy(&mut self, len: usize) {
        // The branch on needs_drop() is an -O1 performance optimization.
        // Without the branch, dropping TypedArena<u8> takes linear time.
        if intrinsics::needs_drop::<T>() {
            let mut start = self.start();
            // Destroy all allocated objects.
            for _ in 0..len {
                ptr::drop_in_place(start);
                start = start.offset(1);
            }
        }
    }

    // Returns a pointer to the first allocated object.
    #[inline]
    fn start(&self) -> *mut T {
        self.storage.ptr()
    }

    // Returns a pointer to the end of the allocated space.
    #[inline]
    fn end(&self) -> *mut T {
        unsafe {
            if mem::size_of::<T>() == 0 {
                // A pointer as large as possible for zero-sized elements.
                !0 as *mut T
            } else {
                self.start().offset(self.storage.cap() as isize)
            }
        }
    }
}

const PAGE: usize = 4096;

impl<T> TypedArena<T> {
    /// Creates a new `TypedArena`.
    #[inline]
    pub fn new() -> TypedArena<T> {
        TypedArena {
            // We set both `ptr` and `end` to 0 so that the first call to
            // alloc() will trigger a grow().
            ptr: Cell::new(0 as *mut T),
            end: Cell::new(0 as *mut T),
            chunks: RefCell::new(vec![]),
            _own: PhantomData,
        }
    }

    /// Allocates an object in the `TypedArena`, returning a reference to it.
    #[inline]
    pub fn alloc(&self, object: T) -> &mut T {
        if self.ptr == self.end {
            self.grow()
        }

        unsafe {
            if mem::size_of::<T>() == 0 {
                self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
                let ptr = heap::EMPTY as *mut T;
                // Don't drop the object. This `write` is equivalent to `forget`.
                ptr::write(ptr, object);
                &mut *ptr
            } else {
                let ptr = self.ptr.get();
                // Advance the pointer.
                self.ptr.set(self.ptr.get().offset(1));
                // Write into uninitialized memory.
                ptr::write(ptr, object);
                &mut *ptr
            }
        }
    }

    /// Grows the arena.
    #[inline(never)]
    #[cold]
    fn grow(&self) {
        unsafe {
            let mut chunks = self.chunks.borrow_mut();
            let (chunk, new_capacity);
            if let Some(last_chunk) = chunks.last_mut() {
                if last_chunk.storage.double_in_place() {
                    self.end.set(last_chunk.end());
                    return;
                } else {
                    let prev_capacity = last_chunk.storage.cap();
                    new_capacity = prev_capacity.checked_mul(2).unwrap();
                }
            } else {
                let elem_size = cmp::max(1, mem::size_of::<T>());
                new_capacity = cmp::max(1, PAGE / elem_size);
            }
            chunk = TypedArenaChunk::<T>::new(new_capacity);
            self.ptr.set(chunk.start());
            self.end.set(chunk.end());
            chunks.push(chunk);
        }
    }

    /// Clears the arena. Deallocates all but the longest chunk which may be reused.
    pub fn clear(&mut self) {
        unsafe {
            // Clear the last chunk, which is partially filled.
            let mut chunks_borrow = self.chunks.borrow_mut();
            if let Some(mut last_chunk) = chunks_borrow.pop() {
                self.clear_last_chunk(&mut last_chunk);
                // If `T` is ZST, code below has no effect.
                for mut chunk in chunks_borrow.drain(..) {
                    let cap = chunk.storage.cap();
                    chunk.destroy(cap);
                }
                chunks_borrow.push(last_chunk);
            }
        }
    }

    // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
    // chunks.
    fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
        // Determine how much was filled.
        let start = last_chunk.start() as usize;
        // We obtain the value of the pointer to the first uninitialized element.
        let end = self.ptr.get() as usize;
        // We then calculate the number of elements to be dropped in the last chunk,
        // which is the filled area's length.
        let diff = if mem::size_of::<T>() == 0 {
            // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
            // the number of zero-sized values in the last and only chunk, just out of caution.
            // Recall that `end` was incremented for each allocated value.
            end - start
        } else {
            (end - start) / mem::size_of::<T>()
        };
        // Pass that to the `destroy` method.
        unsafe {
            last_chunk.destroy(diff);
        }
        // Reset the chunk.
        self.ptr.set(last_chunk.start());
    }
}

impl<T> Drop for TypedArena<T> {
    #[unsafe_destructor_blind_to_params]
    fn drop(&mut self) {
        unsafe {
            // Determine how much was filled.
            let mut chunks_borrow = self.chunks.borrow_mut();
            if let Some(mut last_chunk) = chunks_borrow.pop() {
                // Drop the contents of the last chunk.
                self.clear_last_chunk(&mut last_chunk);
                // The last chunk will be dropped. Destroy all other chunks.
                for chunk in chunks_borrow.iter_mut() {
                    let cap = chunk.storage.cap();
                    chunk.destroy(cap);
                }
            }
            // RawVec handles deallocation of `last_chunk` and `self.chunks`.
        }
    }
}

unsafe impl<T: Send> Send for TypedArena<T> {}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use super::TypedArena;
    use std::cell::Cell;

    #[allow(dead_code)]
    #[derive(Debug, Eq, PartialEq)]
    struct Point {
        x: i32,
        y: i32,
        z: i32,
    }

    #[test]
    pub fn test_unused() {
        let arena: TypedArena<Point> = TypedArena::new();
        assert!(arena.chunks.borrow().is_empty());
    }

    #[test]
    fn test_arena_alloc_nested() {
        struct Inner {
            value: u8,
        }
        struct Outer<'a> {
            inner: &'a Inner,
        }
        enum EI<'e> {
            I(Inner),
            O(Outer<'e>),
        }

        struct Wrap<'a>(TypedArena<EI<'a>>);

        impl<'a> Wrap<'a> {
            fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
                let r: &EI = self.0.alloc(EI::I(f()));
                if let &EI::I(ref i) = r {
                    i
                } else {
                    panic!("mismatch");
                }
            }
            fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
                let r: &EI = self.0.alloc(EI::O(f()));
                if let &EI::O(ref o) = r {
                    o
                } else {
                    panic!("mismatch");
                }
            }
        }

        let arena = Wrap(TypedArena::new());

        let result = arena.alloc_outer(|| {
            Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }
        });

        assert_eq!(result.inner.value, 10);
    }

    #[test]
    pub fn test_copy() {
        let arena = TypedArena::new();
        for _ in 0..100000 {
            arena.alloc(Point { x: 1, y: 2, z: 3 });
        }
    }

    #[bench]
    pub fn bench_copy(b: &mut Bencher) {
        let arena = TypedArena::new();
        b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 }))
    }

    #[bench]
    pub fn bench_copy_nonarena(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 });
        })
    }

    #[allow(dead_code)]
    struct Noncopy {
        string: String,
        array: Vec<i32>,
    }

    #[test]
    pub fn test_noncopy() {
        let arena = TypedArena::new();
        for _ in 0..100000 {
            arena.alloc(Noncopy {
                string: "hello world".to_string(),
                array: vec![1, 2, 3, 4, 5],
            });
        }
    }

    #[test]
    pub fn test_typed_arena_zero_sized() {
        let arena = TypedArena::new();
        for _ in 0..100000 {
            arena.alloc(());
        }
    }

    #[test]
    pub fn test_typed_arena_clear() {
        let mut arena = TypedArena::new();
        for _ in 0..10 {
            arena.clear();
            for _ in 0..10000 {
                arena.alloc(Point { x: 1, y: 2, z: 3 });
            }
        }
    }

    // Drop tests

    struct DropCounter<'a> {
        count: &'a Cell<u32>,
    }

    impl<'a> Drop for DropCounter<'a> {
        fn drop(&mut self) {
            self.count.set(self.count.get() + 1);
        }
    }

    #[test]
    fn test_typed_arena_drop_count() {
        let counter = Cell::new(0);
        {
            let arena: TypedArena<DropCounter> = TypedArena::new();
            for _ in 0..100 {
                // Allocate something with drop glue to make sure it doesn't leak.
                arena.alloc(DropCounter { count: &counter });
            }
        };
        assert_eq!(counter.get(), 100);
    }

    #[test]
    fn test_typed_arena_drop_on_clear() {
        let counter = Cell::new(0);
        let mut arena: TypedArena<DropCounter> = TypedArena::new();
        for i in 0..10 {
            for _ in 0..100 {
                // Allocate something with drop glue to make sure it doesn't leak.
                arena.alloc(DropCounter { count: &counter });
            }
            arena.clear();
            assert_eq!(counter.get(), i * 100 + 100);
        }
    }

    thread_local! {
        static DROP_COUNTER: Cell<u32> = Cell::new(0)
    }

    struct SmallDroppable;

    impl Drop for SmallDroppable {
        fn drop(&mut self) {
            DROP_COUNTER.with(|c| c.set(c.get() + 1));
        }
    }

    #[test]
    fn test_typed_arena_drop_small_count() {
        DROP_COUNTER.with(|c| c.set(0));
        {
            let arena: TypedArena<SmallDroppable> = TypedArena::new();
            for _ in 0..100 {
                // Allocate something with drop glue to make sure it doesn't leak.
                arena.alloc(SmallDroppable);
            }
            // dropping
        };
        assert_eq!(DROP_COUNTER.with(|c| c.get()), 100);
    }

    #[bench]
    pub fn bench_noncopy(b: &mut Bencher) {
        let arena = TypedArena::new();
        b.iter(|| {
            arena.alloc(Noncopy {
                string: "hello world".to_string(),
                array: vec![1, 2, 3, 4, 5],
            })
        })
    }

    #[bench]
    pub fn bench_noncopy_nonarena(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = Box::new(Noncopy {
                string: "hello world".to_string(),
                array: vec![1, 2, 3, 4, 5],
            });
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix: `Frame::Pos` counts positions in u32<commit_after><|endoftext|>


<commit_before><commit_msg>start new<commit_after>enum MathExp {
    Value(i32),
    Add(Box<MathExp>, Box<MathExp>),
    Minus(Box<MathExp>, Box<MathExp>),
    Multiply(Box<MathExp>, Box<MathExp>),
    Divide(Box<MathExp>, Box<MathExp>),
}

impl MathExp {
    fn evaluate(&mut self) -> i32 {
        match *self {
            MathExp::Value(a) => return a,
            MathExp::Add(a, b) => Box::into_raw(a).evaluate() + Box::into_raw(b).evaluate(),
            MathExp::Minus(a, b) => Box::into_raw(a).evaluate() - Box::into_raw(b).evaluate(),
            MathExp::Multiply(a, b) => Box::into_raw(a).evaluate() * Box::into_raw(b).evaluate(),
            MathExp::Divide(a, b) => Box::into_raw(a).evaluate() / Box::into_raw(b).evaluate(),
        }
    }
}

fn main() {}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implementation of cookie creation and matching as specified by
//! http://tools.ietf.org/html/rfc6265

use cookie_storage::CookieSource;
use pub_domains::PUB_DOMAINS;

use cookie_rs;
use time::{Tm, now, at, Timespec};
use url::Url;
use std::borrow::ToOwned;
use std::i64;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::Duration;
use std::str::FromStr;

/// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL,
/// which cookie-rs and hyper's header parsing do not support.
#[derive(Clone, Debug)]
pub struct Cookie {
    pub cookie: cookie_rs::Cookie,
    pub host_only: bool,
    pub persistent: bool,
    pub creation_time: Tm,
    pub last_access: Tm,
    pub expiry_time: Tm,
}

impl Cookie {
    /// http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &Url, source: CookieSource)
                       -> Option<Cookie> {
        // Step 3
        let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
            (&Some(max_age), _) => (true, at(now().to_timespec() + Duration::seconds(max_age as i64))),
            (_, &Some(expires)) => (true, expires),
            _ => (false, at(Timespec::new(i64::MAX, 0)))
        };

        let url_host = request.host().map(|host| host.serialize()).unwrap_or("".to_owned());

        // Step 4
        let mut domain = cookie.domain.clone().unwrap_or("".to_owned());

        // Step 5
        match PUB_DOMAINS.iter().find(|&x| domain == *x) {
            Some(val) if *val == url_host => domain = "".to_string(),
            Some(_) => return None,
            None => {}
        }

        // Step 6
        let host_only = if !domain.is_empty() {
            if !Cookie::domain_match(&url_host, &domain) {
                return None;
            } else {
                cookie.domain = Some(domain);
                false
            }
        } else {
            cookie.domain = Some(url_host);
            true
        };

        // Step 7
        let mut path = cookie.path.unwrap_or("".to_owned());
        if path.is_empty() || path.char_at(0) != '/' {
            let url_path = request.serialize_path();
            let url_path = url_path.as_ref().map(|path| &**path);
            path = Cookie::default_path(url_path.unwrap_or(""));
        }
        cookie.path = Some(path);

        // Step 10
        if cookie.httponly && source != CookieSource::HTTP {
            return None;
        }

        Some(Cookie {
            cookie: cookie,
            host_only: host_only,
            persistent: persistent,
            creation_time: now(),
            last_access: now(),
            expiry_time: expiry_time,
        })
    }

    pub fn touch(&mut self) {
        self.last_access = now();
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    fn default_path(request_path: &str) -> String {
        if request_path == "" || request_path.char_at(0) != '/' ||
           request_path.chars().filter(|&c| c == '/').count() == 1 {
            "/".to_owned()
        } else if request_path.ends_with("/") {
            request_path[..request_path.len() - 1].to_owned()
        } else {
            request_path.to_owned()
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
        request_path == cookie_path ||
        ( request_path.starts_with(cookie_path) &&
            ( request_path.ends_with("/") || request_path.char_at(cookie_path.len() - 1) == '/' )
        )
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.3
    pub fn domain_match(string: &str, domain_string: &str) -> bool {
        if string == domain_string {
            return true;
        }
        if string.ends_with(domain_string)
            && string.char_at(string.len()-domain_string.len()-1) == '.'
            && Ipv4Addr::from_str(string).is_err()
            && Ipv6Addr::from_str(string).is_err() {
            return true;
        }
        false
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
    pub fn appropriate_for_url(&self, url: &Url, source: CookieSource) -> bool {
        let domain = url.host().map(|host| host.serialize());
        if self.host_only {
            if self.cookie.domain != domain {
                return false;
            }
        } else {
            if let (Some(ref domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                if !Cookie::domain_match(domain, cookie_domain) {
                    return false;
                }
            }
        }

        if let (Some(ref path), &Some(ref cookie_path)) = (url.serialize_path(), &self.cookie.path) {
            if !Cookie::path_match(path, cookie_path) {
                return false;
            }
        }

        if self.cookie.secure && url.scheme != "https".to_string() {
            return false;
        }
        if self.cookie.httponly && source == CookieSource::NonHTTP {
            return false;
        }

        return true;
    }
}

#[test]
fn test_domain_match() {
    assert!(Cookie::domain_match("foo.com", "foo.com"));
    assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
    assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));

    assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
    assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
    assert!(!Cookie::domain_match("foo.com", "bar.com"));

    assert!(!Cookie::domain_match("bar.com", "bbar.com"));
    assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
    assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
    assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
}

#[test]
fn test_default_path() {
    assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
    assert!(&*Cookie::default_path("/foo/") == "/foo");
    assert!(&*Cookie::default_path("/foo") == "/");
    assert!(&*Cookie::default_path("/") == "/");
    assert!(&*Cookie::default_path("") == "/");
    assert!(&*Cookie::default_path("foo") == "/");
}

#[test]
fn fn_cookie_constructor() {
    use cookie_storage::CookieSource;

    let url = &Url::parse("http://example.com/foo").unwrap();

    let gov_url = &Url::parse("http://gov.ac/foo").unwrap();
    // cookie name/value test
    assert!(cookie_rs::Cookie::parse(" baz ").is_err());
    assert!(cookie_rs::Cookie::parse(" = bar  ").is_err());
    assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());

    // cookie domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  ").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(&**cookie.cookie.domain.as_ref().unwrap() == "example.com");

    // cookie public domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  gov.ac").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
    assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());

    // cookie domain matching test
    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(cookie.cookie.value.as_slice() == "bar");
    assert!(cookie.cookie.name.as_slice() == "baz");
    assert!(cookie.cookie.secure);
    assert!(cookie.cookie.path.as_ref().unwrap().as_slice() == "/foo/bar/");
    assert!(cookie.cookie.domain.as_ref().unwrap().as_slice() == "example.com");
    assert!(cookie.host_only);

    let u = &Url::parse("http://example.com/foobar").unwrap();
    let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
    assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
}
<commit_msg>Improve and fix default_path cookie algorithm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implementation of cookie creation and matching as specified by
//! http://tools.ietf.org/html/rfc6265

use cookie_storage::CookieSource;
use pub_domains::PUB_DOMAINS;

use cookie_rs;
use time::{Tm, now, at, Timespec};
use url::Url;
use std::borrow::ToOwned;
use std::i64;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::Duration;
use std::str::FromStr;

/// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL,
/// which cookie-rs and hyper's header parsing do not support.
#[derive(Clone, Debug)]
pub struct Cookie {
    pub cookie: cookie_rs::Cookie,
    pub host_only: bool,
    pub persistent: bool,
    pub creation_time: Tm,
    pub last_access: Tm,
    pub expiry_time: Tm,
}

impl Cookie {
    /// http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &Url, source: CookieSource)
                       -> Option<Cookie> {
        // Step 3
        let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
            (&Some(max_age), _) => (true, at(now().to_timespec() + Duration::seconds(max_age as i64))),
            (_, &Some(expires)) => (true, expires),
            _ => (false, at(Timespec::new(i64::MAX, 0)))
        };

        let url_host = request.host().map(|host| host.serialize()).unwrap_or("".to_owned());

        // Step 4
        let mut domain = cookie.domain.clone().unwrap_or("".to_owned());

        // Step 5
        match PUB_DOMAINS.iter().find(|&x| domain == *x) {
            Some(val) if *val == url_host => domain = "".to_string(),
            Some(_) => return None,
            None => {}
        }

        // Step 6
        let host_only = if !domain.is_empty() {
            if !Cookie::domain_match(&url_host, &domain) {
                return None;
            } else {
                cookie.domain = Some(domain);
                false
            }
        } else {
            cookie.domain = Some(url_host);
            true
        };

        // Step 7
        let mut path = cookie.path.unwrap_or("".to_owned());
        if path.is_empty() || path.char_at(0) != '/' {
            let url_path = request.serialize_path();
            let url_path = url_path.as_ref().map(|path| &**path);
            path = Cookie::default_path(url_path.unwrap_or("")).to_owned();
        }
        cookie.path = Some(path);

        // Step 10
        if cookie.httponly && source != CookieSource::HTTP {
            return None;
        }

        Some(Cookie {
            cookie: cookie,
            host_only: host_only,
            persistent: persistent,
            creation_time: now(),
            last_access: now(),
            expiry_time: expiry_time,
        })
    }

    pub fn touch(&mut self) {
        self.last_access = now();
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    fn default_path(request_path: &str) -> &str {
        // Step 2
        if request_path.is_empty() || !request_path.starts_with("/") {
            return "/";
        }

        // Step 3
        let rightmost_slash_idx = request_path.rfind("/").unwrap();
        if rightmost_slash_idx == 0 {
            // There's only one slash; it's the first character
            return "/";
        }

        // Step 4
        &request_path[..rightmost_slash_idx]
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
        request_path == cookie_path ||
        ( request_path.starts_with(cookie_path) &&
            ( request_path.ends_with("/") || request_path.char_at(cookie_path.len() - 1) == '/' )
        )
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.3
    pub fn domain_match(string: &str, domain_string: &str) -> bool {
        if string == domain_string {
            return true;
        }
        if string.ends_with(domain_string)
            && string.char_at(string.len()-domain_string.len()-1) == '.'
            && Ipv4Addr::from_str(string).is_err()
            && Ipv6Addr::from_str(string).is_err() {
            return true;
        }
        false
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
    pub fn appropriate_for_url(&self, url: &Url, source: CookieSource) -> bool {
        let domain = url.host().map(|host| host.serialize());
        if self.host_only {
            if self.cookie.domain != domain {
                return false;
            }
        } else {
            if let (Some(ref domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                if !Cookie::domain_match(domain, cookie_domain) {
                    return false;
                }
            }
        }

        if let (Some(ref path), &Some(ref cookie_path)) = (url.serialize_path(), &self.cookie.path) {
            if !Cookie::path_match(path, cookie_path) {
                return false;
            }
        }

        if self.cookie.secure && url.scheme != "https".to_string() {
            return false;
        }
        if self.cookie.httponly && source == CookieSource::NonHTTP {
            return false;
        }

        return true;
    }
}

#[test]
fn test_domain_match() {
    assert!(Cookie::domain_match("foo.com", "foo.com"));
    assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
    assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));

    assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
    assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
    assert!(!Cookie::domain_match("foo.com", "bar.com"));

    assert!(!Cookie::domain_match("bar.com", "bbar.com"));
    assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
    assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
    assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
}

#[test]
fn test_default_path() {
    assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
    assert!(&*Cookie::default_path("/foo/bar/baz") == "/foo/bar");
    assert!(&*Cookie::default_path("/foo/") == "/foo");
    assert!(&*Cookie::default_path("/foo") == "/");
    assert!(&*Cookie::default_path("/") == "/");
    assert!(&*Cookie::default_path("") == "/");
    assert!(&*Cookie::default_path("foo") == "/");
}

#[test]
fn fn_cookie_constructor() {
    use cookie_storage::CookieSource;

    let url = &Url::parse("http://example.com/foo").unwrap();

    let gov_url = &Url::parse("http://gov.ac/foo").unwrap();
    // cookie name/value test
    assert!(cookie_rs::Cookie::parse(" baz ").is_err());
    assert!(cookie_rs::Cookie::parse(" = bar  ").is_err());
    assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());

    // cookie domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  ").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(&**cookie.cookie.domain.as_ref().unwrap() == "example.com");

    // cookie public domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  gov.ac").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
    assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());

    // cookie domain matching test
    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(cookie.cookie.value.as_slice() == "bar");
    assert!(cookie.cookie.name.as_slice() == "baz");
    assert!(cookie.cookie.secure);
    assert!(cookie.cookie.path.as_ref().unwrap().as_slice() == "/foo/bar/");
    assert!(cookie.cookie.domain.as_ref().unwrap().as_slice() == "example.com");
    assert!(cookie.host_only);

    let u = &Url::parse("http://example.com/foobar").unwrap();
    let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
    assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
}
<|endoftext|>


<commit_before><commit_msg>define and print constants and static<commit_after><|endoftext|>


<commit_before><commit_msg>Add porblem #85<commit_after>use common::problem::{ Problem };

pub static problem: Problem<'static> = Problem {
    id: 85,
    answer: "2772",
    solver: solve
};

// x by y => C = (1 + 2 + .. + x) * (1 + 2 + .. + y) recutangulars
//             = (x (1 + x) / 2) * (y (1 + y)) / 2
//             = xy (1 + x)(1 + y) / 4
fn count_rect((x, y): (uint, uint)) -> uint {
    x * y * (1 + x) * (1 + y) / 4
}

fn uint_diff(a: uint, target: uint) -> uint {
    if a > target { a - target } else { target - a }
}

fn min_idx(i_a: (uint, uint), i_b: (uint, uint), target: uint) -> (uint, uint) {
    let val_a = count_rect(i_a);
    let val_b = count_rect(i_b);

    let diff_a = uint_diff(val_a, target);
    let diff_b = uint_diff(val_b, target);
    if diff_a < diff_b {
        return i_a;
    }
    return i_b;
}

fn solve() -> ~str {
    let target = 2000000;

    let mut x = 1;
    let mut y = 1;

    let mut nearest = (0, 0);

    while count_rect((x, y)) < target { x += 1; y += 1; }
    while count_rect((x - 1, y)) >= target { x -= 1; }
    nearest = min_idx(nearest, (x, y), target);
    if y > 1 { nearest = min_idx(nearest, (x, y - 1), target); }
    y += 1;

    while x > 1 {
        let old_x = x;
        while count_rect((x - 1, y)) >= target { x -= 1; }
        if x != old_x {
            nearest = min_idx(nearest, (x, y), target);
            if y > 1 { nearest = min_idx(nearest, (x, y - 1), target); }
        }
        y += 1;
    }

    while count_rect((x, y + 1)) < target { y += 1; }
    nearest = min_idx(nearest, (x, y), target);

    let (x, y) = nearest;
    return (x * y).to_str();
}
<|endoftext|>


<commit_before><commit_msg>Ignore the final test on anagram (only the first test should run on first download)<commit_after><|endoftext|>


<commit_before><commit_msg>Actually add device module<commit_after>use cocoa::base::{id, nil};
use sys::{MTLCreateSystemDefaultDevice, MTLDevice};
use std::default::Default;
use std::ptr;

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, ()> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil {
            Ok(Device(device))
        } else {
            Err(())
        }
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() != 0 }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() != 0 }
    }
}
<|endoftext|>


<commit_before><commit_msg>Use resiter::IterInnerOkOrElse instead of libimagerror version<commit_after><|endoftext|>


<commit_before><commit_msg>minor formatting.<commit_after><|endoftext|>


<commit_before><commit_msg>Adding chapter 10<commit_after><|endoftext|>


<commit_before><commit_msg>Remove some unsafe code.<commit_after><|endoftext|>


<commit_before><commit_msg>Simplify diffuse shading computation<commit_after><|endoftext|>


<commit_before><commit_msg>Tests<commit_after>// Copyright 2014 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.

// Test method calls with self as an argument

static mut COUNT: u64 = 1;

struct Foo;

trait Bar {
    fn foo1(&self);
    fn foo2(self);
    fn foo3(self: Box<Self>);

    fn bar1(&self) {
        unsafe { COUNT *= 7; }
    }
    fn bar2(self) {
        unsafe { COUNT *= 11; }
    }
    fn bar3(self: Box<Self>) {
        unsafe { COUNT *= 13; }
    }
}

impl Bar for Foo {
    fn foo1(&self) {
        unsafe { COUNT *= 2; }
    }

    fn foo2(self) {
        unsafe { COUNT *= 3; }
    }

    fn foo3(self: Box<Foo>) {
        unsafe { COUNT *= 5; }
    }
}

impl Foo {
    fn baz(self) {
        unsafe { COUNT *= 17; }
        // Test internal call.
        Bar::foo1(&self);
        Bar::foo2(self);
        Bar::foo3(box self);

        Bar::bar1(&self);
        Bar::bar2(self);
        Bar::bar3(box self);
    }
}

fn main() {
    let x = Foo;
    // Test external call.
    Bar::foo1(&x);
    Bar::foo2(x);
    Bar::foo3(box x);

    Bar::bar1(&x);
    Bar::bar2(x);
    Bar::bar3(box x);

    x.baz();

    unsafe { assert!(COUNT == 2u64*2*3*3*5*5*7*7*11*11*13*13*17); }
}
<|endoftext|>


<commit_before><commit_msg>speed things up with a BinaryHeap<commit_after><|endoftext|>


<commit_before>// Copyright 2014 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.

//! The core prelude
//!
//! This module is intended for users of libcore which do not link to libstd as
//! well. This module is imported by default when `#![no_std]` is used in the
//! same manner as the standard library's prelude.

#![stable(feature = "core_prelude", since = "1.4.0")]

// Re-exported core operators
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use marker::{Copy, Send, Sized, Sync};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use ops::{Drop, Fn, FnMut, FnOnce};

// Re-exported functions
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use mem::drop;
#[unstable(feature = "convert_id_prelude", issue = "0")]
#[doc(no_inline)]
pub use convert::id;

// Re-exported types and traits
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use clone::Clone;
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use convert::{AsRef, AsMut, Into, From};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use default::Default;
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use iter::{Iterator, Extend, IntoIterator};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use iter::{DoubleEndedIterator, ExactSizeIterator};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use option::Option::{self, Some, None};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use result::Result::{self, Ok, Err};
<commit_msg>Drop `identity` from prelude.<commit_after>// Copyright 2014 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.

//! The core prelude
//!
//! This module is intended for users of libcore which do not link to libstd as
//! well. This module is imported by default when `#![no_std]` is used in the
//! same manner as the standard library's prelude.

#![stable(feature = "core_prelude", since = "1.4.0")]

// Re-exported core operators
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use marker::{Copy, Send, Sized, Sync};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use ops::{Drop, Fn, FnMut, FnOnce};

// Re-exported functions
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use mem::drop;

// Re-exported types and traits
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use clone::Clone;
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use convert::{AsRef, AsMut, Into, From};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use default::Default;
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use iter::{Iterator, Extend, IntoIterator};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use iter::{DoubleEndedIterator, ExactSizeIterator};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use option::Option::{self, Some, None};
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
pub use result::Result::{self, Ok, Err};
<|endoftext|>