<commit_before>use std::io::Error as IoError;
use std::io::Read;

pub use parse::ParseError;

mod enums;
mod parse;

pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
    where R: Read
{
    let mut data = Vec::new();
    try!(spirv.read_to_end(&mut data));

    // now parsing the document
    let doc = try!(parse::parse_spirv(&data));

    let mut output = String::new();

    {
        // contains the data that was passed as input to this function
        let spirv_data = data.iter().map(|&byte| byte.to_string())
                             .collect::<Vec<String>>()
                             .join(", ");

        // writing the header
        output.push_str(&format!(r#"
pub struct {name} {{
    shader: ::std::sync::Arc<::vulkano::shader::ShaderModule>,
}}

impl {name} {{
    /// Loads the shader in Vulkan as a `ShaderModule`.
    #[inline]
    pub fn load(device: &::std::sync::Arc<::vulkano::Device>) -> {name} {{

        "#, name = name));

        // checking whether each required capability is supported by the vulkan implementation
        for i in doc.instructions.iter() {
            if let &parse::Instruction::Capability(ref cap) = i {
                output.push_str(&format!(r#"
                    if !device.is_capability_supported("{cap}") {{
                        return Err(CapabilityNotSupported);
                    }}"#, cap = capability_name(cap)));
            }
        }

        // follow-up of the header
        output.push_str(&format!(r#"
        unsafe {{
            let data = [{spirv_data}];

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data)
            }}
        }}
    }}

    /// Returns the module that was created.
    #[inline]
    pub fn module(&self) -> &::std::sync::Arc<::vulkano::shader::ShaderModule> {{
        &self.shader
    }}
        "#, name = name, spirv_data = spirv_data));

        // writing one method for each entry point of this module
        for instruction in doc.instructions.iter() {
            if let &parse::Instruction::EntryPoint { .. } = instruction {
                output.push_str(&write_entry_point(&doc, instruction));
            }
        }

        // footer
        output.push_str(&format!(r#"
}}
        "#));
    }

    // TODO: remove
    println!("{:#?}", doc);

    Ok(output)
}

#[derive(Debug)]
pub enum Error {
    IoError(IoError),
    ParseError(ParseError),
}

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

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

fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
    let (execution, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
            (execution, name, interface)
        },
        _ => unreachable!()
    };

    let ty = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            format!("::vulkano::shader::VertexShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            format!("::vulkano::shader::TessControlShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            format!("::vulkano::shader::TessEvaluationShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            format!("::vulkano::shader::GeometryShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let mut output_types = Vec::new();

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassOutput, .. }
                                    if &result_id == interface =>
                        {
                            output_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            format!("::vulkano::shader::FragmentShaderEntryPoint<({output})>",
                    output = output_types.join(", ") + ",")
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            format!("::vulkano::shader::ComputeShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    format!(r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];
            self.shader.entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _))
        }}
    }}
            "#, ep_name = ep_name, ep_name_lenp1 = ep_name.chars().count() + 1, ty = ty,
                encoded_ep_name = ep_name.chars().map(|c| (c as u32).to_string())
                                         .collect::<Vec<String>>().join(", "))
}

fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeVoid { result_id } if result_id == searched => {
                return "()".to_owned()
            },
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return "bool".to_owned()
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                return "i32".to_owned()
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                return "f32".to_owned()
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                let t = type_from_id(doc, component_id);
                return format!("[{}; {}]", t, count);
            },
            &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, depth, arrayed, ms, sampled, ref format, ref access } if result_id == searched => {
                return format!("{}{}Texture{:?}{}{:?}",
                    if ms { "Multisample" } else { "" },
                    if depth == Some(true) { "Depth" } else { "" },
                    dim,
                    if arrayed { "Array" } else { "" },
                    format);
            },
            &parse::Instruction::TypeSampledImage { result_id, image_type_id } if result_id == searched => {
                return type_from_id(doc, image_type_id);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                let len = doc.instructions.iter().filter_map(|e| {
                    match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
                }).next().expect("failed to find array length");
                let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
                return format!("[{}; {}]", t, len);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                return format!("[{}]", t);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = name_from_id(doc, result_id);
                let members = member_types.iter().enumerate().map(|(offset, &member)| {
                    let ty = type_from_id(doc, member);
                    let name = member_name_from_id(doc, result_id, offset as u32);
                    format!("\t{}: {}", name, ty)
                }).collect::<Vec<_>>();
                return format!("struct {} {{\n{}\n}}", name, members.join(",\n"));
            },
            &parse::Instruction::TypeOpaque { result_id, ref name } if result_id == searched => {
                return "<opaque>".to_owned();
            },
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == searched => {
                return type_from_id(doc, type_id);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}

fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::Name { target_id, ref name } = i {
            if target_id == searched {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
            if target_id == searched && member == searched_member {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

// TODO: this function is a draft, as the actual names may not be the same
fn capability_name(cap: &enums::Capability) -> &'static str {
    match *cap {
        enums::Capability::CapabilityMatrix => "Matrix",
        enums::Capability::CapabilityShader => "Shader",
        enums::Capability::CapabilityGeometry => "Geometry",
        enums::Capability::CapabilityTessellation => "Tessellation",
        enums::Capability::CapabilityAddresses => "Addresses",
        enums::Capability::CapabilityLinkage => "Linkage",
        enums::Capability::CapabilityKernel => "Kernel",
        enums::Capability::CapabilityVector16 => "Vector16",
        enums::Capability::CapabilityFloat16Buffer => "Float16Buffer",
        enums::Capability::CapabilityFloat16 => "Float16",
        enums::Capability::CapabilityFloat64 => "Float64",
        enums::Capability::CapabilityInt64 => "Int64",
        enums::Capability::CapabilityInt64Atomics => "Int64Atomics",
        enums::Capability::CapabilityImageBasic => "ImageBasic",
        enums::Capability::CapabilityImageReadWrite => "ImageReadWrite",
        enums::Capability::CapabilityImageMipmap => "ImageMipmap",
        enums::Capability::CapabilityPipes => "Pipes",
        enums::Capability::CapabilityGroups => "Groups",
        enums::Capability::CapabilityDeviceEnqueue => "DeviceEnqueue",
        enums::Capability::CapabilityLiteralSampler => "LiteralSampler",
        enums::Capability::CapabilityAtomicStorage => "AtomicStorage",
        enums::Capability::CapabilityInt16 => "Int16",
        enums::Capability::CapabilityTessellationPointSize => "TessellationPointSize",
        enums::Capability::CapabilityGeometryPointSize => "GeometryPointSize",
        enums::Capability::CapabilityImageGatherExtended => "ImageGatherExtended",
        enums::Capability::CapabilityStorageImageMultisample => "StorageImageMultisample",
        enums::Capability::CapabilityUniformBufferArrayDynamicIndexing => "UniformBufferArrayDynamicIndexing",
        enums::Capability::CapabilitySampledImageArrayDynamicIndexing => "SampledImageArrayDynamicIndexing",
        enums::Capability::CapabilityStorageBufferArrayDynamicIndexing => "StorageBufferArrayDynamicIndexing",
        enums::Capability::CapabilityStorageImageArrayDynamicIndexing => "StorageImageArrayDynamicIndexing",
        enums::Capability::CapabilityClipDistance => "ClipDistance",
        enums::Capability::CapabilityCullDistance => "CullDistance",
        enums::Capability::CapabilityImageCubeArray => "ImageCubeArray",
        enums::Capability::CapabilitySampleRateShading => "SampleRateShading",
        enums::Capability::CapabilityImageRect => "ImageRect",
        enums::Capability::CapabilitySampledRect => "SampledRect",
        enums::Capability::CapabilityGenericPointer => "GenericPointer",
        enums::Capability::CapabilityInt8 => "Int8",
        enums::Capability::CapabilityInputAttachment => "InputAttachment",
        enums::Capability::CapabilitySparseResidency => "SparseResidency",
        enums::Capability::CapabilityMinLod => "MinLod",
        enums::Capability::CapabilitySampled1D => "Sampled1D",
        enums::Capability::CapabilityImage1D => "Image1D",
        enums::Capability::CapabilitySampledCubeArray => "SampledCubeArray",
        enums::Capability::CapabilitySampledBuffer => "SampledBuffer",
        enums::Capability::CapabilityImageBuffer => "ImageBuffer",
        enums::Capability::CapabilityImageMSArray => "ImageMSArray",
        enums::Capability::CapabilityStorageImageExtendedFormats => "StorageImageExtendedFormats",
        enums::Capability::CapabilityImageQuery => "ImageQuery",
        enums::Capability::CapabilityDerivativeControl => "DerivativeControl",
        enums::Capability::CapabilityInterpolationFunction => "InterpolationFunction",
        enums::Capability::CapabilityTransformFeedback => "TransformFeedback",
        enums::Capability::CapabilityGeometryStreams => "GeometryStreams",
        enums::Capability::CapabilityStorageImageReadWithoutFormat => "StorageImageReadWithoutFormat",
        enums::Capability::CapabilityStorageImageWriteWithoutFormat => "StorageImageWriteWithoutFormat",
    }
}
<commit_msg>Add input attribute types to vertex shader type<commit_after>use std::io::Error as IoError;
use std::io::Read;

pub use parse::ParseError;

mod enums;
mod parse;

pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
    where R: Read
{
    let mut data = Vec::new();
    try!(spirv.read_to_end(&mut data));

    // now parsing the document
    let doc = try!(parse::parse_spirv(&data));

    let mut output = String::new();

    {
        // contains the data that was passed as input to this function
        let spirv_data = data.iter().map(|&byte| byte.to_string())
                             .collect::<Vec<String>>()
                             .join(", ");

        // writing the header
        output.push_str(&format!(r#"
pub struct {name} {{
    shader: ::std::sync::Arc<::vulkano::shader::ShaderModule>,
}}

impl {name} {{
    /// Loads the shader in Vulkan as a `ShaderModule`.
    #[inline]
    pub fn load(device: &::std::sync::Arc<::vulkano::Device>) -> {name} {{

        "#, name = name));

        // checking whether each required capability is supported by the vulkan implementation
        for i in doc.instructions.iter() {
            if let &parse::Instruction::Capability(ref cap) = i {
                output.push_str(&format!(r#"
                    if !device.is_capability_supported("{cap}") {{
                        return Err(CapabilityNotSupported);
                    }}"#, cap = capability_name(cap)));
            }
        }

        // follow-up of the header
        output.push_str(&format!(r#"
        unsafe {{
            let data = [{spirv_data}];

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data)
            }}
        }}
    }}

    /// Returns the module that was created.
    #[inline]
    pub fn module(&self) -> &::std::sync::Arc<::vulkano::shader::ShaderModule> {{
        &self.shader
    }}
        "#, name = name, spirv_data = spirv_data));

        // writing one method for each entry point of this module
        for instruction in doc.instructions.iter() {
            if let &parse::Instruction::EntryPoint { .. } = instruction {
                output.push_str(&write_entry_point(&doc, instruction));
            }
        }

        // footer
        output.push_str(&format!(r#"
}}
        "#));
    }

    // TODO: remove
    println!("{:#?}", doc);

    Ok(output)
}

#[derive(Debug)]
pub enum Error {
    IoError(IoError),
    ParseError(ParseError),
}

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

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

fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
    let (execution, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
            (execution, name, interface)
        },
        _ => unreachable!()
    };

    let ty = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            let mut input_types = Vec::new();

            // TODO: sort types by location

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassInput, .. }
                                    if &result_id == interface =>
                        {
                            input_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            format!("::vulkano::shader::VertexShaderEntryPoint<({input})>",
                    input = input_types.join(", ") + ",")
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            format!("::vulkano::shader::TessControlShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            format!("::vulkano::shader::TessEvaluationShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            format!("::vulkano::shader::GeometryShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let mut output_types = Vec::new();

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassOutput, .. }
                                    if &result_id == interface =>
                        {
                            output_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            format!("::vulkano::shader::FragmentShaderEntryPoint<({output})>",
                    output = output_types.join(", ") + ",")
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            format!("::vulkano::shader::ComputeShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    format!(r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];
            self.shader.entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _))
        }}
    }}
            "#, ep_name = ep_name, ep_name_lenp1 = ep_name.chars().count() + 1, ty = ty,
                encoded_ep_name = ep_name.chars().map(|c| (c as u32).to_string())
                                         .collect::<Vec<String>>().join(", "))
}

fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeVoid { result_id } if result_id == searched => {
                return "()".to_owned()
            },
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return "bool".to_owned()
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                return "i32".to_owned()
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                return "f32".to_owned()
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                let t = type_from_id(doc, component_id);
                return format!("[{}; {}]", t, count);
            },
            &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, depth, arrayed, ms, sampled, ref format, ref access } if result_id == searched => {
                return format!("{}{}Texture{:?}{}{:?}",
                    if ms { "Multisample" } else { "" },
                    if depth == Some(true) { "Depth" } else { "" },
                    dim,
                    if arrayed { "Array" } else { "" },
                    format);
            },
            &parse::Instruction::TypeSampledImage { result_id, image_type_id } if result_id == searched => {
                return type_from_id(doc, image_type_id);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                let len = doc.instructions.iter().filter_map(|e| {
                    match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
                }).next().expect("failed to find array length");
                let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
                return format!("[{}; {}]", t, len);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                return format!("[{}]", t);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = name_from_id(doc, result_id);
                let members = member_types.iter().enumerate().map(|(offset, &member)| {
                    let ty = type_from_id(doc, member);
                    let name = member_name_from_id(doc, result_id, offset as u32);
                    format!("\t{}: {}", name, ty)
                }).collect::<Vec<_>>();
                return format!("struct {} {{\n{}\n}}", name, members.join(",\n"));
            },
            &parse::Instruction::TypeOpaque { result_id, ref name } if result_id == searched => {
                return "<opaque>".to_owned();
            },
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == searched => {
                return type_from_id(doc, type_id);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}

fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::Name { target_id, ref name } = i {
            if target_id == searched {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
            if target_id == searched && member == searched_member {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

// TODO: this function is a draft, as the actual names may not be the same
fn capability_name(cap: &enums::Capability) -> &'static str {
    match *cap {
        enums::Capability::CapabilityMatrix => "Matrix",
        enums::Capability::CapabilityShader => "Shader",
        enums::Capability::CapabilityGeometry => "Geometry",
        enums::Capability::CapabilityTessellation => "Tessellation",
        enums::Capability::CapabilityAddresses => "Addresses",
        enums::Capability::CapabilityLinkage => "Linkage",
        enums::Capability::CapabilityKernel => "Kernel",
        enums::Capability::CapabilityVector16 => "Vector16",
        enums::Capability::CapabilityFloat16Buffer => "Float16Buffer",
        enums::Capability::CapabilityFloat16 => "Float16",
        enums::Capability::CapabilityFloat64 => "Float64",
        enums::Capability::CapabilityInt64 => "Int64",
        enums::Capability::CapabilityInt64Atomics => "Int64Atomics",
        enums::Capability::CapabilityImageBasic => "ImageBasic",
        enums::Capability::CapabilityImageReadWrite => "ImageReadWrite",
        enums::Capability::CapabilityImageMipmap => "ImageMipmap",
        enums::Capability::CapabilityPipes => "Pipes",
        enums::Capability::CapabilityGroups => "Groups",
        enums::Capability::CapabilityDeviceEnqueue => "DeviceEnqueue",
        enums::Capability::CapabilityLiteralSampler => "LiteralSampler",
        enums::Capability::CapabilityAtomicStorage => "AtomicStorage",
        enums::Capability::CapabilityInt16 => "Int16",
        enums::Capability::CapabilityTessellationPointSize => "TessellationPointSize",
        enums::Capability::CapabilityGeometryPointSize => "GeometryPointSize",
        enums::Capability::CapabilityImageGatherExtended => "ImageGatherExtended",
        enums::Capability::CapabilityStorageImageMultisample => "StorageImageMultisample",
        enums::Capability::CapabilityUniformBufferArrayDynamicIndexing => "UniformBufferArrayDynamicIndexing",
        enums::Capability::CapabilitySampledImageArrayDynamicIndexing => "SampledImageArrayDynamicIndexing",
        enums::Capability::CapabilityStorageBufferArrayDynamicIndexing => "StorageBufferArrayDynamicIndexing",
        enums::Capability::CapabilityStorageImageArrayDynamicIndexing => "StorageImageArrayDynamicIndexing",
        enums::Capability::CapabilityClipDistance => "ClipDistance",
        enums::Capability::CapabilityCullDistance => "CullDistance",
        enums::Capability::CapabilityImageCubeArray => "ImageCubeArray",
        enums::Capability::CapabilitySampleRateShading => "SampleRateShading",
        enums::Capability::CapabilityImageRect => "ImageRect",
        enums::Capability::CapabilitySampledRect => "SampledRect",
        enums::Capability::CapabilityGenericPointer => "GenericPointer",
        enums::Capability::CapabilityInt8 => "Int8",
        enums::Capability::CapabilityInputAttachment => "InputAttachment",
        enums::Capability::CapabilitySparseResidency => "SparseResidency",
        enums::Capability::CapabilityMinLod => "MinLod",
        enums::Capability::CapabilitySampled1D => "Sampled1D",
        enums::Capability::CapabilityImage1D => "Image1D",
        enums::Capability::CapabilitySampledCubeArray => "SampledCubeArray",
        enums::Capability::CapabilitySampledBuffer => "SampledBuffer",
        enums::Capability::CapabilityImageBuffer => "ImageBuffer",
        enums::Capability::CapabilityImageMSArray => "ImageMSArray",
        enums::Capability::CapabilityStorageImageExtendedFormats => "StorageImageExtendedFormats",
        enums::Capability::CapabilityImageQuery => "ImageQuery",
        enums::Capability::CapabilityDerivativeControl => "DerivativeControl",
        enums::Capability::CapabilityInterpolationFunction => "InterpolationFunction",
        enums::Capability::CapabilityTransformFeedback => "TransformFeedback",
        enums::Capability::CapabilityGeometryStreams => "GeometryStreams",
        enums::Capability::CapabilityStorageImageReadWithoutFormat => "StorageImageReadWithoutFormat",
        enums::Capability::CapabilityStorageImageWriteWithoutFormat => "StorageImageWriteWithoutFormat",
    }
}
<|endoftext|>


<commit_before>extern crate num_cpus;

use std::thread;

pub fn thread_test() -> Result<(), &str> {
    let handle = thread::spawn(|| {
        // println!("Single thread spawned.");
    });

    handle.join().map_err(|err| "Error joining thread.").and_then(|_| Ok(()))
}

pub fn n_threads(n: usize) -> Result<(), &str> {
    let mut handles = Vec::with_capacity(n);
    for _ in 0..n {
        let handle = thread::spawn(move || {
            // println!("Thread {} of {} spawned.", i, n - 1);
        });
        handles.push(handle);
    }
    for handle in handles {
        let _ = handle.join().and_then(|_| Ok(()));
    }
    Ok(())
}

pub fn cpu_count_threads() -> Result<(), &str> {
    let cpu_count = num_cpus::get();
    println!("CPU count: {}", cpu_count);
    let mut handles = Vec::with_capacity(cpu_count);
    for _ in 0..num_cpus::get() {
        let handle = thread::spawn(|| {

        });
        handles.push(handle);
    }
    for handle in handles {
        let _ = handle.join().and_then(|_| Ok(()));
    }
    Ok(())
}

use std::sync::{Arc, Mutex};

pub fn mutating_threads() -> Result<(), &str> {
    const N: usize = 1000;
    let mut handles = Vec::with_capacity(N);
    let data = Arc::new(Mutex::new((0..N).collect::<Vec<usize>>()));

    for i in 0..N {
        let data = data.clone();
        let handle = thread::spawn(move || {
            let mut data = data.lock().expect("Error locking Mutex.");
            data[i] += i;
        });
        handles.push(handle);
    }

    for h in handles {
        if let Err(_) = h.join() {
            return Err("Joining child thread returned an error.");
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn single_thread_empty_return() {
        assert_eq!(thread_test(), Ok(()));
    }
    #[test]
    fn n_threads_test() {
        assert_eq!(n_threads(1usize), Ok(()));
        assert_eq!(n_threads(2usize), Ok(()));
        assert_eq!(n_threads(4usize), Ok(()));
        assert_eq!(n_threads(8usize), Ok(()));
        assert_eq!(n_threads(16usize), Ok(()));
        assert_eq!(n_threads(32usize), Ok(()));
        assert_eq!(n_threads(64usize), Ok(()));
        assert_eq!(n_threads(128usize), Ok(()));
    }
    #[test]
    fn cpu_count_threads_test() {
        assert_eq!(cpu_count_threads(), Ok(()));
    }
    #[test]
    fn mutating_threads_test() {
        assert_eq!(mutating_threads(), Ok(()));
    }
}
<commit_msg>Added mspc::channel examples to thread_testing<commit_after>extern crate num_cpus;

use std::thread;

pub fn thread_test() -> Result<(), String> {
    let handle = thread::spawn(|| {
        // println!("Single thread spawned.");
    });

    handle.join().map_err(|_| "Error joining thread.".to_string()).and_then(|_| Ok(()))
}

pub fn n_threads(n: usize) -> Result<(), String> {
    let mut handles = Vec::with_capacity(n);
    for _ in 0..n {
        let handle = thread::spawn(move || {
            // println!("Thread {} of {} spawned.", i, n - 1);
        });
        handles.push(handle);
    }
    for handle in handles {
        let _ = handle.join().and_then(|_| Ok(()));
    }
    Ok(())
}

pub fn cpu_count_threads() -> Result<(), String> {
    let cpu_count = num_cpus::get();
    println!("CPU count: {}", cpu_count);
    let mut handles = Vec::with_capacity(cpu_count);
    for _ in 0..num_cpus::get() {
        let handle = thread::spawn(|| {

        });
        handles.push(handle);
    }
    for handle in handles {
        let _ = handle.join().and_then(|_| Ok(()));
    }
    Ok(())
}

use std::sync::{Arc, Mutex};

pub fn mutating_threads() -> Result<(), String> {
    const N: usize = 1000;
    let mut handles = Vec::with_capacity(N);
    let data = Arc::new(Mutex::new((0..N).collect::<Vec<usize>>()));

    for i in 0..N {
        let data = data.clone();
        let handle = thread::spawn(move || {
            let mut data = data.lock().expect("Error locking Mutex.");
            data[i] += i;
        });
        handles.push(handle);
    }

    for h in handles {
        if let Err(_) = h.join() {
            return Err("Joining child thread returned an error.".to_string());
        }
    }
    Ok(())
}

use std::sync::mpsc;

pub fn channels_threads() -> Result<(), String> {
    let (tx, rx) = mpsc::channel();

    for i in 0..10 {
        let tx = tx.clone();

        thread::spawn(move || {
            let answer = i * i;

            tx.send(answer).expect("Error sending over channel");
        });
    }

    for _ in 0..10 {
        println!("{}", rx.recv().expect("Error receiving over channel"));
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn single_thread_empty_return() {
        assert_eq!(thread_test(), Ok(()));
    }
    #[test]
    fn n_threads_test() {
        assert_eq!(n_threads(1usize), Ok(()));
        assert_eq!(n_threads(2usize), Ok(()));
        assert_eq!(n_threads(4usize), Ok(()));
        assert_eq!(n_threads(8usize), Ok(()));
        assert_eq!(n_threads(16usize), Ok(()));
        assert_eq!(n_threads(32usize), Ok(()));
        assert_eq!(n_threads(64usize), Ok(()));
        assert_eq!(n_threads(128usize), Ok(()));
    }
    #[test]
    fn cpu_count_threads_test() {
        assert_eq!(cpu_count_threads(), Ok(()));
    }
    #[test]
    fn mutating_threads_test() {
        assert_eq!(mutating_threads(), Ok(()));
    }

    #[test]
    fn channels_test() {
        assert_eq!(channels_threads(), Ok(()));
    }
}
<|endoftext|>


<commit_before>//! Timeline split.

#![deny(missing_docs)]

use graphics::*;
use rect::Rect;

const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];

struct TimelineSplitSettings {
    rect: [f64; 4],
    margin: f64,
    left: f64,
    right: f64,
    top: f64,
}

struct TimelineSplitLayout {
    left: [f64; 4],
    middle: [f64; 4],
    right: [f64; 4],
}

impl TimelineSplitSettings {
    fn call(&self) -> Option<TimelineSplitLayout> {
        let inside = self.rect.margin(self.margin);
        // Use the same size of goto start and goto end buttons as the height
        // of frames.
        let rest = if inside.h() < self.top {
                0.0
            } else {
                inside.h() - self.top
            };
        let (left, middle, right) = inside.split_left_right_margin(
            rest, rest, self.margin
        );
        Some(TimelineSplitLayout {
            left: left,
            middle: middle,
            right: right
        })
    }
}

fn draw_box<G: Graphics>(color: [f32; 4], rect: [f64; 4], c: &Context, g: &mut G) {
    Rectangle::new_border(color, 0.5)
        .draw(rect, &c.draw_state, c.transform, g);
}

/// Test drawing for timeline split.
pub fn test_draw_timeline<G: Graphics>(rect: [u32; 4], c: &Context, g: &mut G) {
    let top = 20.0;
    let top_factor = 0.3;
    if let Some(layout) =
        (TimelineSplitSettings {
            rect: Rect::from_u32(rect),
            margin: 4.0,
            left: 40.0,
            right: 40.0,
            top: top,
        }).call() {

        draw_box(BLUE, layout.left, c, g);
        draw_box(BLUE, layout.middle, c, g);
        draw_box(BLUE, layout.right, c, g);

        let (_, left) = layout.left.split_top(top, top_factor);
        draw_box(RED, left, c, g);
        let (_, middle) = layout.middle.split_top(top, top_factor);
        draw_box(RED, middle, c, g);
        let (_, right) = layout.right.split_top(top, top_factor);
        draw_box(RED, right, c, g);
    }
}
<commit_msg>Renaming<commit_after>//! Timeline split.

#![deny(missing_docs)]

use graphics::*;
use rect::Rect;

const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];

///
pub struct TimelineSplitInput {
    rect: [f64; 4],
    margin: f64,
    left: f64,
    right: f64,
    top: f64,
}

struct TimelineSplitOutput {
    left: [f64; 4],
    middle: [f64; 4],
    right: [f64; 4],
}

impl TimelineSplitInput {
    fn call(&self) -> Option<TimelineSplitOutput> {
        let inside = self.rect.margin(self.margin);
        // Use the same size of goto start and goto end buttons as the height
        // of frames.
        let rest = if inside.h() < self.top {
                0.0
            } else {
                inside.h() - self.top
            };
        let (left, middle, right) = inside.split_left_right_margin(
            rest, rest, self.margin
        );
        Some(TimelineSplitOutput {
            left: left,
            middle: middle,
            right: right
        })
    }
}

fn draw_box<G: Graphics>(color: [f32; 4], rect: [f64; 4], c: &Context, g: &mut G) {
    Rectangle::new_border(color, 0.5)
        .draw(rect, &c.draw_state, c.transform, g);
}

/// Test drawing for timeline split.
pub fn test_draw_timeline<G: Graphics>(rect: [u32; 4], c: &Context, g: &mut G) {
    let top = 20.0;
    let top_factor = 0.3;
    if let Some(layout) =
        (TimelineSplitInput {
            rect: Rect::from_u32(rect),
            margin: 4.0,
            left: 40.0,
            right: 40.0,
            top: top,
        }).call() {

        draw_box(BLUE, layout.left, c, g);
        draw_box(BLUE, layout.middle, c, g);
        draw_box(BLUE, layout.right, c, g);

        let (_, left) = layout.left.split_top(top, top_factor);
        draw_box(RED, left, c, g);
        let (_, middle) = layout.middle.split_top(top, top_factor);
        draw_box(RED, middle, c, g);
        let (_, right) = layout.right.split_top(top, top_factor);
        draw_box(RED, right, c, g);
    }
}
<|endoftext|>


<commit_before>//!
//! TODO: document me

use bindings::*;

pub static PUBKEY_BYTES: uint = 32;
pub static SECKEY_BYTES: uint = 64;
pub static SIGN_BYTES: uint = 64;

pub struct SecretKey ([u8, ..SECKEY_BYTES]);
pub struct PublicKey ([u8, ..PUBKEY_BYTES]);

pub struct SignKey {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl SignKey {
    pub fn new() -> SignKey {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        SignKey { pk: PublicKey(pk), sk: SecretKey(sk) }
    }
}

pub struct Signer {
    pub keypair: SignKey
}

impl Signer {
    pub fn new() -> Signer {
        Signer { keypair: SignKey::new() }
    }

    pub fn new_with_key(key: SignKey) -> Signer {
        Signer { keypair: key }
    }

    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.keypair.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        signed
    }

    pub fn verify(&self, smsg: &[u8], pk: PublicKey) -> Option<Vec<u8>> {
        let mut msg: Vec<u8> = Vec::from_elem(smsg.len(), 0u8);
        let mut msg_len: u64 = 0;

        let PublicKey(pk) = pk;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   smsg.as_ptr(),
                                   smsg.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => fail!("Impossible things happened")
            }
        }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let signer = Signer::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = signer.keypair.sk;
        let PublicKey(pk) = signer.keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = signer.sign(msg.as_slice());
        let desig = signer.verify(sig.as_slice(), signer.keypair.pk);

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let signer = Signer::new();
    let msg = b"some message";

    let other_key = SignKey::new();

    let SecretKey(sk) = signer.keypair.sk;
    let PublicKey(pk) = signer.keypair.pk;

    println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

    let sig = signer.sign(msg);
    let desig = signer.verify(sig.as_slice(), other_key.pk);

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig, desig);

    assert!(desig.is_none());
}
<commit_msg>Change sign API to closer match crypto{box,sign}<commit_after>//!
//!
//! TODO: document me

use bindings::*;

/// Number of bytes in the sign public key
pub static PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub static SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub static SIGN_BYTES: uint = 64;

pub struct PublicKey ([u8, ..PUBKEY_BYTES]);
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    pub pk: PublicKey,
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => fail!("Impossible things happened")
            }
        }
    }
}

/// Matching secret / public keys.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's secret key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: self.pk, signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}
<|endoftext|>


<commit_before>use utils::bigint::{M256, U256};
use utils::address::Address;
use utils::gas::Gas;
use utils::rlp::WriteRLP;

use std::collections::hash_map;
use crypto::sha3::Sha3;
use crypto::digest::Digest;
use super::{VM, Machine, Patch, Log, Account, CommitResult, CommitError,
            ExecutionResult, ExecutionError, AccountCommitment, Storage, Memory,
            BlockHeader, Context};

#[derive(Debug, Clone)]
pub enum Transaction {
    MessageCall(MessageCall),
    ContractCreation(ContractCreation),
}

#[derive(Debug, Clone)]
pub struct ContractCreation {
    pub gas_price: Gas,
    pub gas_limit: Gas,
    pub origin: Address,
    pub caller: Address,
    pub value: U256,
    pub init: Vec<u8>,
}

impl ContractCreation {
    pub fn into_context(self, nonce: M256, depth: usize) -> Context {
        let mut sha3 = Sha3::keccak256();
        let mut rlp: Vec<u8> = Vec::new();
        let mut ret = [0u8; 32];
        self.caller.write_rlp(&mut rlp);
        nonce.write_rlp(&mut rlp);
        sha3.input(rlp.as_slice());
        sha3.result(&mut ret);
        let address = Address::from(M256::from(ret));

        Context {
            address: address,
            caller: self.caller,
            code: self.init,
            data: Vec::new(),
            gas_limit: self.gas_limit,
            gas_price: self.gas_price,
            origin: self.origin,
            value: self.value,
            depth: depth,
        }
    }
}

#[derive(Debug, Clone)]
pub struct MessageCall {
    pub gas_price: Gas,
    pub gas_limit: Gas,
    pub to: Address,
    pub origin: Address,
    pub caller: Address,
    pub value: U256,
    pub data: Vec<u8>,
}

impl MessageCall {
    pub fn into_context(self, code: Vec<u8>, depth: usize) -> Context {
        Context {
            address: self.to,
            caller: self.caller,
            code: code,
            data: self.data,
            gas_limit: self.gas_limit,
            gas_price: self.gas_price,
            origin: self.origin,
            value: self.value,
            depth: depth,
        }
    }
}

pub struct ContractCreationMachine<M, S> {
    machine: Option<Machine<M, S>>,
    transaction: ContractCreation,
    block: BlockHeader,
    depth: usize,

    _empty_logs: Vec<Log>,
    _empty_accounts: hash_map::HashMap<Address, Account<S>>,
    _initial_transactions: [Transaction; 1],
}

impl<M, S> Into<Machine<M, S>> for ContractCreationMachine<M, S> {
    fn into(self) -> Machine<M, S> {
        self.machine.unwrap()
    }
}

impl<M: Memory + Default, S: Storage + Default> ContractCreationMachine<M, S> {
    pub fn new(transaction: ContractCreation, block: BlockHeader, depth: usize) -> Self {
        Self {
            machine: None,
            transaction: transaction.clone(),
            block: block,
            depth: depth,

            _empty_logs: Vec::new(),
            _empty_accounts: hash_map::HashMap::new(),
            _initial_transactions: [Transaction::ContractCreation(transaction)],
        }
    }
}

impl<M: Memory + Default, S: Storage + Default> VM<S> for ContractCreationMachine<M, S> {
    fn peek_cost(&self) -> ExecutionResult<Gas> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_ref().unwrap().peek_cost()
    }

    fn step(&mut self) -> ExecutionResult<()> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_mut().unwrap().step()
    }

    fn commit_account(&mut self, commitment: AccountCommitment<S>) -> CommitResult<()> {
        if self.machine.is_none() {
            match commitment {
                AccountCommitment::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage,
                    code: code,
                } => {
                    if address != self.transaction.caller {
                        return Err(CommitError::Invalid);
                    }

                    let context = self.transaction.clone().into_context(nonce, self.depth);
                    let mut machine = Machine::new(context, self.block.clone());
                    machine.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        storage: storage,
                        code: code
                    });
                    self.machine = Some(machine);
                },
                _ => return Err(CommitError::Invalid),
            }
            return Ok(());
        }
        self.machine.as_mut().unwrap().commit_account(commitment)
    }

    fn commit_blockhash(&mut self, number: M256, hash: M256) -> CommitResult<()> {
        if self.machine.is_none() {
            return Err(CommitError::Invalid);
        }
        self.machine.as_mut().unwrap().commit_blockhash(number, hash)
    }

    fn accounts(&self) -> hash_map::Values<Address, Account<S>> {
        if self.machine.is_none() {
            return self._empty_accounts.values();
        }
        self.machine.as_ref().unwrap().accounts()
    }

    fn transactions(&self) -> &[Transaction] {
        if self.machine.is_none() {
            return &self._initial_transactions;
        }
        self.machine.as_ref().unwrap().transactions()
    }

    fn appending_logs(&self) -> &[Log] {
        if self.machine.is_none() {
            return self._empty_logs.as_slice();
        }
        self.machine.as_ref().unwrap().appending_logs()
    }

    fn patch(&self) -> Patch {
        self.machine.as_ref().unwrap().patch()
    }
}

pub struct MessageCallMachine<M, S> {
    machine: Option<Machine<M, S>>,
    transaction: MessageCall,
    block: BlockHeader,
    depth: usize,

    _empty_logs: Vec<Log>,
    _empty_accounts: hash_map::HashMap<Address, Account<S>>,
    _initial_transactions: [Transaction; 1],
}

impl<M, S> Into<Machine<M, S>> for MessageCallMachine<M, S> {
    fn into(self) -> Machine<M, S> {
        self.machine.unwrap()
    }
}

impl<M: Memory + Default, S: Storage + Default> MessageCallMachine<M, S> {
    pub fn new(transaction: MessageCall, block: BlockHeader, depth: usize) -> Self {
        Self {
            machine: None,
            transaction: transaction.clone(),
            block: block,
            depth: depth,

            _empty_logs: Vec::new(),
            _empty_accounts: hash_map::HashMap::new(),
            _initial_transactions: [Transaction::MessageCall(transaction)],
        }
    }
}

impl<M: Memory + Default, S: Storage + Default> VM<S> for MessageCallMachine<M, S> {
    fn peek_cost(&self) -> ExecutionResult<Gas> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_ref().unwrap().peek_cost()
    }

    fn step(&mut self) -> ExecutionResult<()> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_mut().unwrap().step()
    }

    fn commit_account(&mut self, commitment: AccountCommitment<S>) -> CommitResult<()> {
        if self.machine.is_none() {
            match commitment {
                AccountCommitment::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage,
                    code: code,
                } => {
                    if address != self.transaction.caller {
                        return Err(CommitError::Invalid);
                    }

                    let context = self.transaction.clone().into_context(code.clone(), self.depth);
                    let mut machine = Machine::new(context, self.block.clone());
                    machine.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        storage: storage,
                        code: code
                    });
                    self.machine = Some(machine);
                },
                _ => return Err(CommitError::Invalid),
            }
            return Ok(());
        }
        self.machine.as_mut().unwrap().commit_account(commitment)
    }

    fn commit_blockhash(&mut self, number: M256, hash: M256) -> CommitResult<()> {
        if self.machine.is_none() {
            return Err(CommitError::Invalid);
        }
        self.machine.as_mut().unwrap().commit_blockhash(number, hash)
    }

    fn transactions(&self) -> &[Transaction] {
        if self.machine.is_none() {
            return &self._initial_transactions;
        }
        self.machine.as_ref().unwrap().transactions()
    }

    fn accounts(&self) -> hash_map::Values<Address, Account<S>> {
        if self.machine.is_none() {
            return self._empty_accounts.values();
        }
        self.machine.as_ref().unwrap().accounts()
    }

    fn appending_logs(&self) -> &[Log] {
        if self.machine.is_none() {
            return self._empty_logs.as_slice();
        }
        self.machine.as_ref().unwrap().appending_logs()
    }

    fn patch(&self) -> Patch {
        self.machine.as_ref().unwrap().patch()
    }
}
<commit_msg>Problem: transaction not added to machine Solution: add it when executing a transaction<commit_after>use utils::bigint::{M256, U256};
use utils::address::Address;
use utils::gas::Gas;
use utils::rlp::WriteRLP;

use std::collections::hash_map;
use crypto::sha3::Sha3;
use crypto::digest::Digest;
use super::{VM, Machine, Patch, Log, Account, CommitResult, CommitError,
            ExecutionResult, ExecutionError, AccountCommitment, Storage, Memory,
            BlockHeader, Context};

#[derive(Debug, Clone)]
pub enum Transaction {
    MessageCall(MessageCall),
    ContractCreation(ContractCreation),
}

#[derive(Debug, Clone)]
pub struct ContractCreation {
    pub gas_price: Gas,
    pub gas_limit: Gas,
    pub origin: Address,
    pub caller: Address,
    pub value: U256,
    pub init: Vec<u8>,
}

impl ContractCreation {
    pub fn into_context(self, nonce: M256, depth: usize) -> Context {
        let mut sha3 = Sha3::keccak256();
        let mut rlp: Vec<u8> = Vec::new();
        let mut ret = [0u8; 32];
        self.caller.write_rlp(&mut rlp);
        nonce.write_rlp(&mut rlp);
        sha3.input(rlp.as_slice());
        sha3.result(&mut ret);
        let address = Address::from(M256::from(ret));

        Context {
            address: address,
            caller: self.caller,
            code: self.init,
            data: Vec::new(),
            gas_limit: self.gas_limit,
            gas_price: self.gas_price,
            origin: self.origin,
            value: self.value,
            depth: depth,
        }
    }
}

#[derive(Debug, Clone)]
pub struct MessageCall {
    pub gas_price: Gas,
    pub gas_limit: Gas,
    pub to: Address,
    pub origin: Address,
    pub caller: Address,
    pub value: U256,
    pub data: Vec<u8>,
}

impl MessageCall {
    pub fn into_context(self, code: Vec<u8>, depth: usize) -> Context {
        Context {
            address: self.to,
            caller: self.caller,
            code: code,
            data: self.data,
            gas_limit: self.gas_limit,
            gas_price: self.gas_price,
            origin: self.origin,
            value: self.value,
            depth: depth,
        }
    }
}

pub struct ContractCreationMachine<M, S> {
    machine: Option<Machine<M, S>>,
    transaction: ContractCreation,
    block: BlockHeader,
    depth: usize,

    _empty_logs: Vec<Log>,
    _empty_accounts: hash_map::HashMap<Address, Account<S>>,
    _initial_transactions: [Transaction; 1],
}

impl<M, S> Into<Machine<M, S>> for ContractCreationMachine<M, S> {
    fn into(self) -> Machine<M, S> {
        self.machine.unwrap()
    }
}

impl<M: Memory + Default, S: Storage + Default> ContractCreationMachine<M, S> {
    pub fn new(transaction: ContractCreation, block: BlockHeader, depth: usize) -> Self {
        Self {
            machine: None,
            transaction: transaction.clone(),
            block: block,
            depth: depth,

            _empty_logs: Vec::new(),
            _empty_accounts: hash_map::HashMap::new(),
            _initial_transactions: [Transaction::ContractCreation(transaction)],
        }
    }
}

impl<M: Memory + Default, S: Storage + Default> VM<S> for ContractCreationMachine<M, S> {
    fn peek_cost(&self) -> ExecutionResult<Gas> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_ref().unwrap().peek_cost()
    }

    fn step(&mut self) -> ExecutionResult<()> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_mut().unwrap().step()
    }

    fn commit_account(&mut self, commitment: AccountCommitment<S>) -> CommitResult<()> {
        if self.machine.is_none() {
            match commitment {
                AccountCommitment::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage,
                    code: code,
                } => {
                    if address != self.transaction.caller {
                        return Err(CommitError::Invalid);
                    }

                    let context = self.transaction.clone().into_context(nonce, self.depth);
                    let mut machine = Machine::new(context, self.block.clone());
                    machine.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        storage: storage,
                        code: code
                    });
                    machine.transactions.push(Transaction::ContractCreation(self.transaction.clone()));
                    self.machine = Some(machine);
                },
                _ => return Err(CommitError::Invalid),
            }
            return Ok(());
        }
        self.machine.as_mut().unwrap().commit_account(commitment)
    }

    fn commit_blockhash(&mut self, number: M256, hash: M256) -> CommitResult<()> {
        if self.machine.is_none() {
            return Err(CommitError::Invalid);
        }
        self.machine.as_mut().unwrap().commit_blockhash(number, hash)
    }

    fn accounts(&self) -> hash_map::Values<Address, Account<S>> {
        if self.machine.is_none() {
            return self._empty_accounts.values();
        }
        self.machine.as_ref().unwrap().accounts()
    }

    fn transactions(&self) -> &[Transaction] {
        if self.machine.is_none() {
            return &self._initial_transactions;
        }
        self.machine.as_ref().unwrap().transactions()
    }

    fn appending_logs(&self) -> &[Log] {
        if self.machine.is_none() {
            return self._empty_logs.as_slice();
        }
        self.machine.as_ref().unwrap().appending_logs()
    }

    fn patch(&self) -> Patch {
        self.machine.as_ref().unwrap().patch()
    }
}

pub struct MessageCallMachine<M, S> {
    machine: Option<Machine<M, S>>,
    transaction: MessageCall,
    block: BlockHeader,
    depth: usize,

    _empty_logs: Vec<Log>,
    _empty_accounts: hash_map::HashMap<Address, Account<S>>,
    _initial_transactions: [Transaction; 1],
}

impl<M, S> Into<Machine<M, S>> for MessageCallMachine<M, S> {
    fn into(self) -> Machine<M, S> {
        self.machine.unwrap()
    }
}

impl<M: Memory + Default, S: Storage + Default> MessageCallMachine<M, S> {
    pub fn new(transaction: MessageCall, block: BlockHeader, depth: usize) -> Self {
        Self {
            machine: None,
            transaction: transaction.clone(),
            block: block,
            depth: depth,

            _empty_logs: Vec::new(),
            _empty_accounts: hash_map::HashMap::new(),
            _initial_transactions: [Transaction::MessageCall(transaction)],
        }
    }
}

impl<M: Memory + Default, S: Storage + Default> VM<S> for MessageCallMachine<M, S> {
    fn peek_cost(&self) -> ExecutionResult<Gas> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_ref().unwrap().peek_cost()
    }

    fn step(&mut self) -> ExecutionResult<()> {
        if self.machine.is_none() {
            return Err(ExecutionError::RequireAccount(self.transaction.caller));
        }
        self.machine.as_mut().unwrap().step()
    }

    fn commit_account(&mut self, commitment: AccountCommitment<S>) -> CommitResult<()> {
        if self.machine.is_none() {
            match commitment {
                AccountCommitment::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage,
                    code: code,
                } => {
                    if address != self.transaction.caller {
                        return Err(CommitError::Invalid);
                    }

                    let context = self.transaction.clone().into_context(code.clone(), self.depth);
                    let mut machine = Machine::new(context, self.block.clone());
                    machine.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        storage: storage,
                        code: code
                    });
                    machine.transactions.push(Transaction::MessageCall(self.transaction.clone()));
                    self.machine = Some(machine);
                },
                _ => return Err(CommitError::Invalid),
            }
            return Ok(());
        }
        self.machine.as_mut().unwrap().commit_account(commitment)
    }

    fn commit_blockhash(&mut self, number: M256, hash: M256) -> CommitResult<()> {
        if self.machine.is_none() {
            return Err(CommitError::Invalid);
        }
        self.machine.as_mut().unwrap().commit_blockhash(number, hash)
    }

    fn transactions(&self) -> &[Transaction] {
        if self.machine.is_none() {
            return &self._initial_transactions;
        }
        self.machine.as_ref().unwrap().transactions()
    }

    fn accounts(&self) -> hash_map::Values<Address, Account<S>> {
        if self.machine.is_none() {
            return self._empty_accounts.values();
        }
        self.machine.as_ref().unwrap().accounts()
    }

    fn appending_logs(&self) -> &[Log] {
        if self.machine.is_none() {
            return self._empty_logs.as_slice();
        }
        self.machine.as_ref().unwrap().appending_logs()
    }

    fn patch(&self) -> Patch {
        self.machine.as_ref().unwrap().patch()
    }
}
<|endoftext|>


<commit_before>use std::ops::{BitOr, BitXor};
use super::{chtype, A_ALTCHARSET, A_BLINK, A_BOLD, A_CHARTEXT, A_DIM, A_INVIS, A_LEFTLINE};
use super::{A_ITALIC, A_OVERLINE, A_REVERSE, A_RIGHTLINE, A_STRIKEOUT, A_UNDERLINE};
use super::colorpair::ColorPair;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Attribute {
    AlternativeCharSet,
    Bold,
    Blink,
    CharText,
    Dim,
    Leftline,
    Invisible,
    Italic,
    Normal,
    Overline,
    Reverse,
    Rightline,
    Strikeout,
    Underline,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Attributes {
    raw: chtype,
    color_pair: ColorPair,
}

macro_rules! attribute_setter {
    ($name:ident, $attr:ident) => {
        pub fn $name(&mut self, enabled: bool) {
            if enabled {
                self.raw = self.raw | $attr;
            } else {
                self.raw = self.raw ^ $attr;
            }
        }
    };
}

impl Attributes {
    pub fn new() -> Attributes {
        Attributes {
            raw: 0,
            color_pair: ColorPair(0),
        }
    }

    pub fn is_alternative_char_set(&self) -> bool {
        (self.raw & A_ALTCHARSET) > 0
    }
    attribute_setter!(set_alternative_char_set, A_ALTCHARSET);

    pub fn is_bold(&self) -> bool {
        (self.raw & A_BOLD) > 0
    }
    attribute_setter!(set_bold, A_BOLD);

    pub fn is_blink(&self) -> bool {
        (self.raw & A_BLINK) > 0
    }
    attribute_setter!(set_blink, A_BLINK);

    pub fn is_char_text(&self) -> bool {
        (self.raw & A_CHARTEXT) > 0
    }
    attribute_setter!(set_char_text, A_CHARTEXT);

    pub fn is_dim(&self) -> bool {
        (self.raw & A_DIM) > 0
    }
    attribute_setter!(set_dim, A_DIM);

    pub fn is_leftline(&self) -> bool {
        (self.raw & A_LEFTLINE) > 0
    }
    attribute_setter!(set_leftline, A_LEFTLINE);

    pub fn is_invisible(&self) -> bool {
        (self.raw & A_INVIS) > 0
    }
    attribute_setter!(set_invisible, A_INVIS);

    pub fn is_italic(&self) -> bool {
        (self.raw & A_ITALIC) > 0
    }
    attribute_setter!(set_italic, A_ITALIC);

    pub fn is_normal(&self) -> bool {
        self.raw == 0
    }
    pub fn set_normal(&mut self) {
        self.raw = 0
    }

    pub fn is_overline(&self) -> bool {
        (self.raw & A_OVERLINE) > 0
    }
    attribute_setter!(set_overline, A_OVERLINE);

    pub fn is_reverse(&self) -> bool {
        (self.raw & A_REVERSE) > 0
    }
    attribute_setter!(set_reverse, A_REVERSE);

    pub fn is_rightline(&self) -> bool {
        (self.raw & A_RIGHTLINE) > 0
    }
    attribute_setter!(set_rightline, A_RIGHTLINE);

    pub fn is_strikeout(&self) -> bool {
        (self.raw & A_STRIKEOUT) > 0
    }
    attribute_setter!(set_strikeout, A_STRIKEOUT);

    pub fn is_underline(&self) -> bool {
        (self.raw & A_UNDERLINE) > 0
    }
    attribute_setter!(set_underline, A_UNDERLINE);

    pub fn color_pair(&self) -> ColorPair {
        self.color_pair
    }
    pub fn set_color_pair(&mut self, color_pair: ColorPair) {
        let color_chtype: chtype = color_pair.into();
        self.raw = self.raw | color_chtype;
        self.color_pair = color_pair;
    }
}

/// Implement the | operator for adding an Attribute to Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::new();
/// assert!(!attributes.is_bold());
/// attributes = attributes | Attribute::Bold;
/// assert!(attributes.is_bold());
/// ```
impl BitOr<Attribute> for Attributes {
    type Output = Attributes;

    fn bitor(mut self, rhs: Attribute) -> Attributes {
        match rhs {
            Attribute::AlternativeCharSet => self.set_alternative_char_set(true),
            Attribute::Bold => self.set_bold(true),
            Attribute::Blink => self.set_blink(true),
            Attribute::CharText => self.set_char_text(true),
            Attribute::Dim => self.set_dim(true),
            Attribute::Leftline => self.set_leftline(true),
            Attribute::Invisible => self.set_invisible(true),
            Attribute::Italic => self.set_italic(true),
            Attribute::Normal => self.set_normal(),
            Attribute::Overline => self.set_overline(true),
            Attribute::Reverse => self.set_reverse(true),
            Attribute::Rightline => self.set_rightline(true),
            Attribute::Strikeout => self.set_strikeout(true),
            Attribute::Underline => self.set_underline(true),
        }
        self
    }
}

/// Implement the ^ operator for disabling an Attribute from Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::from(Attribute::Bold);
/// assert!(attributes.is_bold());
/// attributes = attributes ^ Attribute::Bold;
/// assert!(!attributes.is_bold());
/// ```
impl BitXor<Attribute> for Attributes {
    type Output = Attributes;

    fn bitxor(mut self, rhs: Attribute) -> Attributes {
        match rhs {
            Attribute::AlternativeCharSet => self.set_alternative_char_set(false),
            Attribute::Bold => self.set_bold(false),
            Attribute::Blink => self.set_blink(false),
            Attribute::CharText => self.set_char_text(false),
            Attribute::Dim => self.set_dim(false),
            Attribute::Leftline => self.set_leftline(false),
            Attribute::Invisible => self.set_invisible(false),
            Attribute::Italic => self.set_italic(false),
            Attribute::Normal => (),
            Attribute::Overline => self.set_overline(false),
            Attribute::Reverse => self.set_reverse(false),
            Attribute::Rightline => self.set_rightline(false),
            Attribute::Strikeout => self.set_strikeout(false),
            Attribute::Underline => self.set_underline(false),
        }
        self
    }
}

/// Implement the | operator for adding Attributes to Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::new() | Attribute::Bold;
/// let other = Attributes::new() | Attribute::Reverse;
/// attributes = attributes | other;
/// assert!(attributes.is_bold());
/// assert!(attributes.is_reverse());
/// assert!(!attributes.is_italic());
/// ```
impl BitOr for Attributes {
    type Output = Attributes;

    fn bitor(self, rhs: Attributes) -> Attributes {
        Attributes {
            raw: self.raw | rhs.raw,
            color_pair: ColorPair(self.color_pair.0 | rhs.color_pair.0),
        }
    }
}

/// Implement the ^ operator for removing Attributes from Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::new() | Attribute::Blink | Attribute::Bold;
/// let other = Attributes::new() | Attribute::Reverse | Attribute::Bold;
/// attributes = attributes ^ other;
/// assert!(!attributes.is_bold());
/// assert!(attributes.is_reverse());
/// assert!(attributes.is_blink());
/// ```
impl BitXor for Attributes {
    type Output = Attributes;

    fn bitxor(self, rhs: Attributes) -> Attributes {
        Attributes {
            raw: self.raw ^ rhs.raw,
            color_pair: ColorPair(self.color_pair.0 ^ rhs.color_pair.0),
        }
    }
}

/// Implement the | operator for combining two 'Attribute's into Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let attributes = Attribute::Blink | Attribute::Reverse;
/// assert!(!attributes.is_bold());
/// assert!(attributes.is_blink());
/// assert!(attributes.is_reverse());
/// ```
impl BitOr for Attribute {
    type Output = Attributes;

    fn bitor(self, rhs: Attribute) -> Attributes {
        Attributes::new() | self | rhs
    }
}

/// Implement Default for Attributes
///
/// # Example
///
/// ```
/// use pancurses::Attributes;
/// let attributes: Attributes = Default::default();
/// assert_eq!(attributes, Attributes::new());
/// ```
impl Default for Attributes {
    fn default() -> Self {
        Self::new()
    }
}

impl From<Attribute> for Attributes {
    fn from(attribute: Attribute) -> Attributes {
        Attributes::new() | attribute
    }
}

impl From<Attribute> for chtype {
    fn from(attribute: Attribute) -> chtype {
        chtype::from(Attributes::from(attribute))
    }
}

impl From<Attributes> for chtype {
    fn from(attributes: Attributes) -> chtype {
        attributes.raw
    }
}
<commit_msg>Simplified attribute macro<commit_after>use std::ops::{BitOr, BitXor};
use super::{chtype, A_ALTCHARSET, A_BLINK, A_BOLD, A_CHARTEXT, A_DIM, A_INVIS, A_LEFTLINE};
use super::{A_ITALIC, A_OVERLINE, A_REVERSE, A_RIGHTLINE, A_STRIKEOUT, A_UNDERLINE};
use super::colorpair::ColorPair;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Attribute {
    AlternativeCharSet,
    Bold,
    Blink,
    CharText,
    Dim,
    Leftline,
    Invisible,
    Italic,
    Normal,
    Overline,
    Reverse,
    Rightline,
    Strikeout,
    Underline,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Attributes {
    raw: chtype,
    color_pair: ColorPair,
}

macro_rules! attribute_setter {
    ($name:ident, $attr:ident) => {
        pub fn $name(&mut self, enabled: bool) {
            if enabled {
                self.raw |= $attr;
            } else {
                self.raw ^= $attr;
            }
        }
    };
}

impl Attributes {
    pub fn new() -> Attributes {
        Attributes {
            raw: 0,
            color_pair: ColorPair(0),
        }
    }

    pub fn is_alternative_char_set(&self) -> bool {
        (self.raw & A_ALTCHARSET) > 0
    }
    attribute_setter!(set_alternative_char_set, A_ALTCHARSET);

    pub fn is_bold(&self) -> bool {
        (self.raw & A_BOLD) > 0
    }
    attribute_setter!(set_bold, A_BOLD);

    pub fn is_blink(&self) -> bool {
        (self.raw & A_BLINK) > 0
    }
    attribute_setter!(set_blink, A_BLINK);

    pub fn is_char_text(&self) -> bool {
        (self.raw & A_CHARTEXT) > 0
    }
    attribute_setter!(set_char_text, A_CHARTEXT);

    pub fn is_dim(&self) -> bool {
        (self.raw & A_DIM) > 0
    }
    attribute_setter!(set_dim, A_DIM);

    pub fn is_leftline(&self) -> bool {
        (self.raw & A_LEFTLINE) > 0
    }
    attribute_setter!(set_leftline, A_LEFTLINE);

    pub fn is_invisible(&self) -> bool {
        (self.raw & A_INVIS) > 0
    }
    attribute_setter!(set_invisible, A_INVIS);

    pub fn is_italic(&self) -> bool {
        (self.raw & A_ITALIC) > 0
    }
    attribute_setter!(set_italic, A_ITALIC);

    pub fn is_normal(&self) -> bool {
        self.raw == 0
    }
    pub fn set_normal(&mut self) {
        self.raw = 0
    }

    pub fn is_overline(&self) -> bool {
        (self.raw & A_OVERLINE) > 0
    }
    attribute_setter!(set_overline, A_OVERLINE);

    pub fn is_reverse(&self) -> bool {
        (self.raw & A_REVERSE) > 0
    }
    attribute_setter!(set_reverse, A_REVERSE);

    pub fn is_rightline(&self) -> bool {
        (self.raw & A_RIGHTLINE) > 0
    }
    attribute_setter!(set_rightline, A_RIGHTLINE);

    pub fn is_strikeout(&self) -> bool {
        (self.raw & A_STRIKEOUT) > 0
    }
    attribute_setter!(set_strikeout, A_STRIKEOUT);

    pub fn is_underline(&self) -> bool {
        (self.raw & A_UNDERLINE) > 0
    }
    attribute_setter!(set_underline, A_UNDERLINE);

    pub fn color_pair(&self) -> ColorPair {
        self.color_pair
    }
    pub fn set_color_pair(&mut self, color_pair: ColorPair) {
        let color_chtype: chtype = color_pair.into();
        self.raw = self.raw | color_chtype;
        self.color_pair = color_pair;
    }
}

/// Implement the | operator for adding an Attribute to Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::new();
/// assert!(!attributes.is_bold());
/// attributes = attributes | Attribute::Bold;
/// assert!(attributes.is_bold());
/// ```
impl BitOr<Attribute> for Attributes {
    type Output = Attributes;

    fn bitor(mut self, rhs: Attribute) -> Attributes {
        match rhs {
            Attribute::AlternativeCharSet => self.set_alternative_char_set(true),
            Attribute::Bold => self.set_bold(true),
            Attribute::Blink => self.set_blink(true),
            Attribute::CharText => self.set_char_text(true),
            Attribute::Dim => self.set_dim(true),
            Attribute::Leftline => self.set_leftline(true),
            Attribute::Invisible => self.set_invisible(true),
            Attribute::Italic => self.set_italic(true),
            Attribute::Normal => self.set_normal(),
            Attribute::Overline => self.set_overline(true),
            Attribute::Reverse => self.set_reverse(true),
            Attribute::Rightline => self.set_rightline(true),
            Attribute::Strikeout => self.set_strikeout(true),
            Attribute::Underline => self.set_underline(true),
        }
        self
    }
}

/// Implement the ^ operator for disabling an Attribute from Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::from(Attribute::Bold);
/// assert!(attributes.is_bold());
/// attributes = attributes ^ Attribute::Bold;
/// assert!(!attributes.is_bold());
/// ```
impl BitXor<Attribute> for Attributes {
    type Output = Attributes;

    fn bitxor(mut self, rhs: Attribute) -> Attributes {
        match rhs {
            Attribute::AlternativeCharSet => self.set_alternative_char_set(false),
            Attribute::Bold => self.set_bold(false),
            Attribute::Blink => self.set_blink(false),
            Attribute::CharText => self.set_char_text(false),
            Attribute::Dim => self.set_dim(false),
            Attribute::Leftline => self.set_leftline(false),
            Attribute::Invisible => self.set_invisible(false),
            Attribute::Italic => self.set_italic(false),
            Attribute::Normal => (),
            Attribute::Overline => self.set_overline(false),
            Attribute::Reverse => self.set_reverse(false),
            Attribute::Rightline => self.set_rightline(false),
            Attribute::Strikeout => self.set_strikeout(false),
            Attribute::Underline => self.set_underline(false),
        }
        self
    }
}

/// Implement the | operator for adding Attributes to Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::new() | Attribute::Bold;
/// let other = Attributes::new() | Attribute::Reverse;
/// attributes = attributes | other;
/// assert!(attributes.is_bold());
/// assert!(attributes.is_reverse());
/// assert!(!attributes.is_italic());
/// ```
impl BitOr for Attributes {
    type Output = Attributes;

    fn bitor(self, rhs: Attributes) -> Attributes {
        Attributes {
            raw: self.raw | rhs.raw,
            color_pair: ColorPair(self.color_pair.0 | rhs.color_pair.0),
        }
    }
}

/// Implement the ^ operator for removing Attributes from Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let mut attributes = Attributes::new() | Attribute::Blink | Attribute::Bold;
/// let other = Attributes::new() | Attribute::Reverse | Attribute::Bold;
/// attributes = attributes ^ other;
/// assert!(!attributes.is_bold());
/// assert!(attributes.is_reverse());
/// assert!(attributes.is_blink());
/// ```
impl BitXor for Attributes {
    type Output = Attributes;

    fn bitxor(self, rhs: Attributes) -> Attributes {
        Attributes {
            raw: self.raw ^ rhs.raw,
            color_pair: ColorPair(self.color_pair.0 ^ rhs.color_pair.0),
        }
    }
}

/// Implement the | operator for combining two 'Attribute's into Attributes
///
/// # Example
///
/// ```
/// use pancurses::{Attribute, Attributes};
///
/// let attributes = Attribute::Blink | Attribute::Reverse;
/// assert!(!attributes.is_bold());
/// assert!(attributes.is_blink());
/// assert!(attributes.is_reverse());
/// ```
impl BitOr for Attribute {
    type Output = Attributes;

    fn bitor(self, rhs: Attribute) -> Attributes {
        Attributes::new() | self | rhs
    }
}

/// Implement Default for Attributes
///
/// # Example
///
/// ```
/// use pancurses::Attributes;
/// let attributes: Attributes = Default::default();
/// assert_eq!(attributes, Attributes::new());
/// ```
impl Default for Attributes {
    fn default() -> Self {
        Self::new()
    }
}

impl From<Attribute> for Attributes {
    fn from(attribute: Attribute) -> Attributes {
        Attributes::new() | attribute
    }
}

impl From<Attribute> for chtype {
    fn from(attribute: Attribute) -> chtype {
        chtype::from(Attributes::from(attribute))
    }
}

impl From<Attributes> for chtype {
    fn from(attributes: Attributes) -> chtype {
        attributes.raw
    }
}
<|endoftext|>