<commit_before>// Copyright 2016 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{mem, ptr};
use d3dcompiler;
use dxguid;
use winapi;
use gfx_core as core;
use gfx_core::shade as s;

pub fn reflect_shader(code: &[u8]) -> *mut winapi::ID3D11ShaderReflection {
    let mut reflection = ptr::null_mut();
    let hr = unsafe {
        d3dcompiler::D3DReflect(code.as_ptr() as *const winapi::VOID,
            code.len() as winapi::SIZE_T, &dxguid::IID_ID3D11ShaderReflection, &mut reflection)
    };
    if winapi::SUCCEEDED(hr) {
        reflection as *mut winapi::ID3D11ShaderReflection
    }else {
        panic!("Shader reflection failed with code {:x}", hr);
    }
}

fn convert_str(pchar: *const i8) -> String {
    use std::ffi::CStr;
    unsafe {
        CStr::from_ptr(pchar).to_string_lossy().into_owned()
    }
}

fn map_base_type_from_component(ct: winapi::D3D_REGISTER_COMPONENT_TYPE) -> s::BaseType {
    match ct {
        winapi::D3D_REGISTER_COMPONENT_UINT32 => s::BaseType::U32,
        winapi::D3D_REGISTER_COMPONENT_SINT32 => s::BaseType::I32,
        winapi::D3D_REGISTER_COMPONENT_FLOAT32 => s::BaseType::F32,
        winapi::D3D_REGISTER_COMPONENT_TYPE(t) => {
            error!("Unknown register component type {} detected!", t);
            s::BaseType::F32
        }
    }
}

fn map_base_type_from_return(rt: winapi::D3D_RESOURCE_RETURN_TYPE) -> s::BaseType {
    match rt {
        winapi::D3D_RETURN_TYPE_UINT => s::BaseType::U32,
        winapi::D3D_RETURN_TYPE_SINT => s::BaseType::I32,
        winapi::D3D_RETURN_TYPE_FLOAT => s::BaseType::F32,
        winapi::D3D_RESOURCE_RETURN_TYPE(t) => {
            error!("Unknown return type {} detected!", t);
            s::BaseType::F32
        }
    }
}

fn map_texture_type(tt: winapi::D3D_SRV_DIMENSION) -> s::TextureType {
    use winapi::*;
    use gfx_core::shade::IsArray::*;
    use gfx_core::shade::IsMultiSample::*;
    match tt {
        D3D_SRV_DIMENSION_BUFFER            => s::TextureType::Buffer,
        D3D_SRV_DIMENSION_TEXTURE1D         => s::TextureType::D1(NoArray),
        D3D_SRV_DIMENSION_TEXTURE1DARRAY    => s::TextureType::D1(Array),
        D3D_SRV_DIMENSION_TEXTURE2D         => s::TextureType::D2(NoArray, NoMultiSample),
        D3D_SRV_DIMENSION_TEXTURE2DARRAY    => s::TextureType::D2(Array, NoMultiSample),
        D3D_SRV_DIMENSION_TEXTURE2DMS       => s::TextureType::D2(NoArray, MultiSample),
        D3D_SRV_DIMENSION_TEXTURE2DMSARRAY  => s::TextureType::D2(Array, MultiSample),
        D3D_SRV_DIMENSION_TEXTURE3D         => s::TextureType::D3,
        D3D_SRV_DIMENSION_TEXTURECUBE       => s::TextureType::Cube(NoArray),
        D3D_SRV_DIMENSION_TEXTURECUBEARRAY  => s::TextureType::Cube(Array),
        D3D_SRV_DIMENSION(t) => {
            error!("Unknow texture dimension {}", t);
            s::TextureType::Buffer
        }
    }
}

fn map_container(class: winapi::D3D_SHADER_VARIABLE_CLASS, rows: u32, cols: u32) -> s::ContainerType {
    use gfx_core::shade::Dimension as Dim;
    //TODO: use `match` when winapi allows
    if class == winapi::D3D_SVC_SCALAR {
        s::ContainerType::Single
    } else if class == winapi::D3D_SVC_VECTOR {
        s::ContainerType::Vector(cols as Dim)
    } else if class == winapi::D3D_SVC_MATRIX_ROWS {
        s::ContainerType::Matrix(s::MatrixFormat::RowMajor, rows as Dim, cols as Dim)
    } else if class == winapi::D3D_SVC_MATRIX_COLUMNS {
        s::ContainerType::Matrix(s::MatrixFormat::ColumnMajor, rows as Dim, cols as Dim)
    } else  {
        error!("Unexpected class to classify as container: {:?}", class);
        s::ContainerType::Single
    }
}

fn map_base_type(_svt: winapi::D3D_SHADER_VARIABLE_TYPE) -> s::BaseType {
    s::BaseType::F32 //TODO
}

pub fn populate_info(info: &mut s::ProgramInfo, stage: s::Stage,
                     reflection: *mut winapi::ID3D11ShaderReflection) {
    use winapi::{UINT, SUCCEEDED};
    let usage = stage.into();
    let (shader_desc, _feature_level) = unsafe {
        let mut desc = mem::zeroed();
        let mut level = winapi::D3D_FEATURE_LEVEL_9_1;
        (*reflection).GetDesc(&mut desc);
        (*reflection).GetMinFeatureLevel(&mut level);
        (desc, level)
    };
    fn mask_to_vector(mask: u8) -> s::ContainerType {
        s::ContainerType::Vector(match mask {
            0...1 => 1,
            2...3 => 2,
            4...7 => 3,
            _ => 4,
        })
    }
    if stage == s::Stage::Vertex {
        // record vertex attributes
        for i in 0 .. shader_desc.InputParameters {
            let (hr, desc) = unsafe {
                let mut desc = mem::zeroed();
                let hr = (*reflection).GetInputParameterDesc(i as UINT, &mut desc);
                (hr, desc)
            };
            assert!(SUCCEEDED(hr));
            info!("\tAttribute {}, system type {:?}, mask {}, read-write mask {}",
                convert_str(desc.SemanticName), desc.SystemValueType, desc.Mask, desc.ReadWriteMask);
            if desc.SystemValueType != winapi::D3D_NAME_UNDEFINED {
                // system value semantic detected, skipping
                continue
            }
            if desc.Mask == 0 {
                // not used, skipping
                continue
            }
            let name = convert_str(desc.SemanticName);
            if desc.SemanticIndex != 0 {
                error!("Semantic {} has non-zero index {} - not supported by the backend", name, desc.SemanticIndex);
            }
            info.vertex_attributes.push(s::AttributeVar {
                name: name,
                slot: desc.Register as core::AttributeSlot,
                base_type: map_base_type_from_component(desc.ComponentType),
                container: mask_to_vector(desc.Mask),
            });
        }
    }
    if stage == s::Stage::Pixel {
        // record pixel outputs
        for i in 0 .. shader_desc.OutputParameters {
            let (hr, desc) = unsafe {
                let mut desc = mem::zeroed();
                let hr = (*reflection).GetOutputParameterDesc(i as UINT, &mut desc);
                (hr, desc)
            };
            assert!(SUCCEEDED(hr));
            let name = convert_str(desc.SemanticName);
            info!("\tOutput {}, system type {:?}, mask {}, read-write mask {}",
                name, desc.SystemValueType, desc.Mask, desc.ReadWriteMask);
            match desc.SystemValueType {
                winapi::D3D_NAME_TARGET =>
                    info.outputs.push(s::OutputVar {
                        name: format!("Target{}", desc.SemanticIndex), //care!
                        slot: desc.Register as core::ColorSlot,
                        base_type: map_base_type_from_component(desc.ComponentType),
                        container: mask_to_vector(desc.Mask),
                    }),
                winapi::D3D_NAME_DEPTH => info.output_depth = true,
                winapi::D3D_NAME_UNDEFINED =>
                    warn!("Custom PS output semantic is ignored: {}", name),
                _ =>
                    warn!("Unhandled PS output semantic {} of type {:?}", name, desc.SystemValueType),
            }
        }
    }
    // record resources
    for i in 0 .. shader_desc.BoundResources {
        let (hr, res_desc) = unsafe {
            let mut desc = mem::zeroed();
            let hr = (*reflection).GetResourceBindingDesc(i as UINT, &mut desc);
            (hr, desc)
        };
        assert!(SUCCEEDED(hr));
        let name = convert_str(res_desc.Name);
        info!("\tResource {}, type {:?}", name, res_desc.Type);
        if res_desc.Type == winapi::D3D_SIT_CBUFFER {
            if let Some(cb) = info.constant_buffers.iter_mut().find(|cb| cb.name == name) {
                cb.usage = cb.usage | usage;
                continue;
            }
            let cbuf = unsafe {
                (*reflection).GetConstantBufferByName(res_desc.Name)
            };
            let desc = unsafe {
                let mut desc = mem::zeroed();
                let hr = (*cbuf).GetDesc(&mut desc);
                assert!(SUCCEEDED(hr));
                desc
            };
            let mut elements = Vec::new();
            for i in 0 .. desc.Variables {
                let var = unsafe {
                    (*cbuf).GetVariableByIndex(i)
                };
                let var_desc = unsafe {
                    let mut vd = mem::zeroed();
                    let hr1 = (*var).GetDesc(&mut vd);
                    assert!(SUCCEEDED(hr1));
                    vd
                };
                let vtype = unsafe {
                    (*var).GetType()
                };
                let vtype_desc = unsafe {
                    let mut vtd = mem::zeroed();
                    let hr2 = (*vtype).GetDesc(&mut vtd);
                    assert!(SUCCEEDED(hr2));
                    vtd
                };
                let el_name = convert_str(var_desc.Name);
                debug!("\t\tElement at {}\t= '{}'", var_desc.StartOffset, el_name);
                if vtype_desc.Class == winapi::D3D_SVC_STRUCT {
                    for j in 0 .. vtype_desc.Members {
                        let member = unsafe {
                            (*vtype).GetMemberTypeByIndex(j)
                        };
                        let mem_name_ptr = unsafe {
                            (*vtype).GetMemberTypeName(j)
                        };
                        let mem_desc = unsafe {
                            let mut mtd = mem::zeroed();
                            let hr3 = (*member).GetDesc(&mut mtd);
                            assert!(SUCCEEDED(hr3));
                            mtd
                        };
                        let mem_name = convert_str(mem_name_ptr); //mem_desc.Name
                        debug!("\t\t\tMember at {}\t= '{}'", mem_desc.Offset, mem_name);
                        let base_offset = var_desc.StartOffset + j * var_desc.Size;
                        elements.push(s::ConstVar {
                            name: format!("{}[{}].{}", el_name, j, mem_name),
                            location: (base_offset + mem_desc.Offset) as s::Location,
                            count: mem_desc.Elements as usize,
                            base_type: map_base_type(mem_desc.Type),
                            container: map_container(mem_desc.Class, mem_desc.Rows, mem_desc.Columns),
                        })
                    }
                } else {
                    elements.push(s::ConstVar {
                        name: el_name,
                        location: var_desc.StartOffset as s::Location,
                        count: vtype_desc.Elements as usize,
                        base_type: map_base_type(vtype_desc.Type),
                        container: map_container(vtype_desc.Class, vtype_desc.Rows, vtype_desc.Columns),
                    })
                }
            }
            info.constant_buffers.push(s::ConstantBufferVar {
                name: name,
                slot: res_desc.BindPoint as core::ConstantBufferSlot,
                size: desc.Size as usize,
                usage: usage,
                elements: elements,
            });
        }else if res_desc.Type == winapi::D3D_SIT_TEXTURE {
            if let Some(t) = info.textures.iter_mut().find(|t| t.name == name) {
                t.usage = t.usage | usage;
                continue;
            }
            info.textures.push(s::TextureVar {
                name: name,
                slot: res_desc.BindPoint as core::ResourceViewSlot,
                base_type: map_base_type_from_return(res_desc.ReturnType),
                ty: map_texture_type(res_desc.Dimension),
                usage: usage,
            });
        }else if res_desc.Type == winapi::D3D_SIT_SAMPLER {
            let name = name.trim_right_matches('_');
            if let Some(s) = info.samplers.iter_mut().find(|s| s.name == name) {
                s.usage = s.usage | usage;
                continue;
            }
            let cmp = if res_desc.uFlags & winapi::D3D_SIF_COMPARISON_SAMPLER.0 != 0 {
                s::IsComparison::Compare
            }else {
                s::IsComparison::NoCompare
            };
            info.samplers.push(s::SamplerVar {
                name: name.to_owned(),
                slot: res_desc.BindPoint as core::SamplerSlot,
                ty: s::SamplerType(cmp, s::IsRect::NoRect),
                usage: usage,
            });
        }else {
            error!("Unsupported resource type {:?} for {}", res_desc.Type, name);
        }
    }
}
<commit_msg>[DX11] fixed the offsets of struct array members<commit_after>// Copyright 2016 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{mem, ptr};
use d3dcompiler;
use dxguid;
use winapi;
use gfx_core as core;
use gfx_core::shade as s;

pub fn reflect_shader(code: &[u8]) -> *mut winapi::ID3D11ShaderReflection {
    let mut reflection = ptr::null_mut();
    let hr = unsafe {
        d3dcompiler::D3DReflect(code.as_ptr() as *const winapi::VOID,
            code.len() as winapi::SIZE_T, &dxguid::IID_ID3D11ShaderReflection, &mut reflection)
    };
    if winapi::SUCCEEDED(hr) {
        reflection as *mut winapi::ID3D11ShaderReflection
    }else {
        panic!("Shader reflection failed with code {:x}", hr);
    }
}

fn convert_str(pchar: *const i8) -> String {
    use std::ffi::CStr;
    unsafe {
        CStr::from_ptr(pchar).to_string_lossy().into_owned()
    }
}

fn map_base_type_from_component(ct: winapi::D3D_REGISTER_COMPONENT_TYPE) -> s::BaseType {
    match ct {
        winapi::D3D_REGISTER_COMPONENT_UINT32 => s::BaseType::U32,
        winapi::D3D_REGISTER_COMPONENT_SINT32 => s::BaseType::I32,
        winapi::D3D_REGISTER_COMPONENT_FLOAT32 => s::BaseType::F32,
        winapi::D3D_REGISTER_COMPONENT_TYPE(t) => {
            error!("Unknown register component type {} detected!", t);
            s::BaseType::F32
        }
    }
}

fn map_base_type_from_return(rt: winapi::D3D_RESOURCE_RETURN_TYPE) -> s::BaseType {
    match rt {
        winapi::D3D_RETURN_TYPE_UINT => s::BaseType::U32,
        winapi::D3D_RETURN_TYPE_SINT => s::BaseType::I32,
        winapi::D3D_RETURN_TYPE_FLOAT => s::BaseType::F32,
        winapi::D3D_RESOURCE_RETURN_TYPE(t) => {
            error!("Unknown return type {} detected!", t);
            s::BaseType::F32
        }
    }
}

fn map_texture_type(tt: winapi::D3D_SRV_DIMENSION) -> s::TextureType {
    use winapi::*;
    use gfx_core::shade::IsArray::*;
    use gfx_core::shade::IsMultiSample::*;
    match tt {
        D3D_SRV_DIMENSION_BUFFER            => s::TextureType::Buffer,
        D3D_SRV_DIMENSION_TEXTURE1D         => s::TextureType::D1(NoArray),
        D3D_SRV_DIMENSION_TEXTURE1DARRAY    => s::TextureType::D1(Array),
        D3D_SRV_DIMENSION_TEXTURE2D         => s::TextureType::D2(NoArray, NoMultiSample),
        D3D_SRV_DIMENSION_TEXTURE2DARRAY    => s::TextureType::D2(Array, NoMultiSample),
        D3D_SRV_DIMENSION_TEXTURE2DMS       => s::TextureType::D2(NoArray, MultiSample),
        D3D_SRV_DIMENSION_TEXTURE2DMSARRAY  => s::TextureType::D2(Array, MultiSample),
        D3D_SRV_DIMENSION_TEXTURE3D         => s::TextureType::D3,
        D3D_SRV_DIMENSION_TEXTURECUBE       => s::TextureType::Cube(NoArray),
        D3D_SRV_DIMENSION_TEXTURECUBEARRAY  => s::TextureType::Cube(Array),
        D3D_SRV_DIMENSION(t) => {
            error!("Unknow texture dimension {}", t);
            s::TextureType::Buffer
        }
    }
}

fn map_container(stype: &winapi::D3D11_SHADER_TYPE_DESC) -> s::ContainerType {
    use gfx_core::shade::Dimension as Dim;
    //TODO: use `match` when winapi allows
    if stype.Class == winapi::D3D_SVC_SCALAR {
        s::ContainerType::Single
    } else if stype.Class == winapi::D3D_SVC_VECTOR {
        s::ContainerType::Vector(stype.Columns as Dim)
    } else if stype.Class == winapi::D3D_SVC_MATRIX_ROWS {
        s::ContainerType::Matrix(s::MatrixFormat::RowMajor, stype.Rows as Dim, stype.Columns as Dim)
    } else if stype.Class == winapi::D3D_SVC_MATRIX_COLUMNS {
        s::ContainerType::Matrix(s::MatrixFormat::ColumnMajor, stype.Rows as Dim, stype.Columns as Dim)
    } else  {
        error!("Unexpected type to classify as container: {:?}", stype);
        s::ContainerType::Single
    }
}

fn map_base_type(_svt: winapi::D3D_SHADER_VARIABLE_TYPE) -> s::BaseType {
    s::BaseType::F32 //TODO
}

pub fn populate_info(info: &mut s::ProgramInfo, stage: s::Stage,
                     reflection: *mut winapi::ID3D11ShaderReflection) {
    use winapi::{UINT, SUCCEEDED};
    let usage = stage.into();
    let (shader_desc, _feature_level) = unsafe {
        let mut desc = mem::zeroed();
        let mut level = winapi::D3D_FEATURE_LEVEL_9_1;
        (*reflection).GetDesc(&mut desc);
        (*reflection).GetMinFeatureLevel(&mut level);
        (desc, level)
    };
    fn mask_to_vector(mask: u8) -> s::ContainerType {
        s::ContainerType::Vector(match mask {
            0...1 => 1,
            2...3 => 2,
            4...7 => 3,
            _ => 4,
        })
    }
    if stage == s::Stage::Vertex {
        // record vertex attributes
        for i in 0 .. shader_desc.InputParameters {
            let (hr, desc) = unsafe {
                let mut desc = mem::zeroed();
                let hr = (*reflection).GetInputParameterDesc(i as UINT, &mut desc);
                (hr, desc)
            };
            assert!(SUCCEEDED(hr));
            info!("\tAttribute {}, system type {:?}, mask {}, read-write mask {}",
                convert_str(desc.SemanticName), desc.SystemValueType, desc.Mask, desc.ReadWriteMask);
            if desc.SystemValueType != winapi::D3D_NAME_UNDEFINED {
                // system value semantic detected, skipping
                continue
            }
            if desc.Mask == 0 {
                // not used, skipping
                continue
            }
            let name = convert_str(desc.SemanticName);
            if desc.SemanticIndex != 0 {
                error!("Semantic {} has non-zero index {} - not supported by the backend", name, desc.SemanticIndex);
            }
            info.vertex_attributes.push(s::AttributeVar {
                name: name,
                slot: desc.Register as core::AttributeSlot,
                base_type: map_base_type_from_component(desc.ComponentType),
                container: mask_to_vector(desc.Mask),
            });
        }
    }
    if stage == s::Stage::Pixel {
        // record pixel outputs
        for i in 0 .. shader_desc.OutputParameters {
            let (hr, desc) = unsafe {
                let mut desc = mem::zeroed();
                let hr = (*reflection).GetOutputParameterDesc(i as UINT, &mut desc);
                (hr, desc)
            };
            assert!(SUCCEEDED(hr));
            let name = convert_str(desc.SemanticName);
            info!("\tOutput {}, system type {:?}, mask {}, read-write mask {}",
                name, desc.SystemValueType, desc.Mask, desc.ReadWriteMask);
            match desc.SystemValueType {
                winapi::D3D_NAME_TARGET =>
                    info.outputs.push(s::OutputVar {
                        name: format!("Target{}", desc.SemanticIndex), //care!
                        slot: desc.Register as core::ColorSlot,
                        base_type: map_base_type_from_component(desc.ComponentType),
                        container: mask_to_vector(desc.Mask),
                    }),
                winapi::D3D_NAME_DEPTH => info.output_depth = true,
                winapi::D3D_NAME_UNDEFINED =>
                    warn!("Custom PS output semantic is ignored: {}", name),
                _ =>
                    warn!("Unhandled PS output semantic {} of type {:?}", name, desc.SystemValueType),
            }
        }
    }
    // record resources
    for i in 0 .. shader_desc.BoundResources {
        let (hr, res_desc) = unsafe {
            let mut desc = mem::zeroed();
            let hr = (*reflection).GetResourceBindingDesc(i as UINT, &mut desc);
            (hr, desc)
        };
        assert!(SUCCEEDED(hr));
        let name = convert_str(res_desc.Name);
        info!("\tResource {}, type {:?}", name, res_desc.Type);
        if res_desc.Type == winapi::D3D_SIT_CBUFFER {
            if let Some(cb) = info.constant_buffers.iter_mut().find(|cb| cb.name == name) {
                cb.usage = cb.usage | usage;
                continue;
            }
            let cbuf = unsafe {
                (*reflection).GetConstantBufferByName(res_desc.Name)
            };
            let desc = unsafe {
                let mut desc = mem::zeroed();
                let hr = (*cbuf).GetDesc(&mut desc);
                assert!(SUCCEEDED(hr));
                desc
            };
            let mut elements = Vec::new();
            for i in 0 .. desc.Variables {
                let var = unsafe {
                    (*cbuf).GetVariableByIndex(i)
                };
                let var_desc = unsafe {
                    let mut vd = mem::zeroed();
                    let hr1 = (*var).GetDesc(&mut vd);
                    assert!(SUCCEEDED(hr1));
                    vd
                };
                let vtype = unsafe {
                    (*var).GetType()
                };
                let vtype_desc = unsafe {
                    let mut vtd = mem::zeroed();
                    let hr2 = (*vtype).GetDesc(&mut vtd);
                    assert!(SUCCEEDED(hr2));
                    vtd
                };
                let el_name = convert_str(var_desc.Name);
                debug!("\t\tElement at {}\t= '{}'", var_desc.StartOffset, el_name);
                if vtype_desc.Class == winapi::D3D_SVC_STRUCT {
                    let stride = var_desc.Size / vtype_desc.Elements;
                    for j in 0 .. vtype_desc.Members {
                        let member = unsafe {
                            (*vtype).GetMemberTypeByIndex(j)
                        };
                        let mem_name_ptr = unsafe {
                            (*vtype).GetMemberTypeName(j)
                        };
                        let mem_desc = unsafe {
                            let mut mtd = mem::zeroed();
                            let hr3 = (*member).GetDesc(&mut mtd);
                            assert!(SUCCEEDED(hr3));
                            mtd
                        };
                        let mem_name = convert_str(mem_name_ptr); //mem_desc.Name
                        debug!("\t\t\tMember at {}\t= '{}'", mem_desc.Offset, mem_name);
                        let btype = map_base_type(mem_desc.Type);
                        let container = map_container(&mem_desc);
                        for k in 0 .. vtype_desc.Elements {
                            let offset = var_desc.StartOffset + k * stride + mem_desc.Offset;
                            elements.push(s::ConstVar {
                                name: format!("{}[{}].{}", el_name, k, mem_name),
                                location: offset as s::Location,
                                count: mem_desc.Elements as usize,
                                base_type: btype,
                                container: container,
                            })
                        }
                    }
                } else {
                    elements.push(s::ConstVar {
                        name: el_name,
                        location: var_desc.StartOffset as s::Location,
                        count: vtype_desc.Elements as usize,
                        base_type: map_base_type(vtype_desc.Type),
                        container: map_container(&vtype_desc),
                    })
                }
            }
            info.constant_buffers.push(s::ConstantBufferVar {
                name: name,
                slot: res_desc.BindPoint as core::ConstantBufferSlot,
                size: desc.Size as usize,
                usage: usage,
                elements: elements,
            });
        }else if res_desc.Type == winapi::D3D_SIT_TEXTURE {
            if let Some(t) = info.textures.iter_mut().find(|t| t.name == name) {
                t.usage = t.usage | usage;
                continue;
            }
            info.textures.push(s::TextureVar {
                name: name,
                slot: res_desc.BindPoint as core::ResourceViewSlot,
                base_type: map_base_type_from_return(res_desc.ReturnType),
                ty: map_texture_type(res_desc.Dimension),
                usage: usage,
            });
        }else if res_desc.Type == winapi::D3D_SIT_SAMPLER {
            let name = name.trim_right_matches('_');
            if let Some(s) = info.samplers.iter_mut().find(|s| s.name == name) {
                s.usage = s.usage | usage;
                continue;
            }
            let cmp = if res_desc.uFlags & winapi::D3D_SIF_COMPARISON_SAMPLER.0 != 0 {
                s::IsComparison::Compare
            }else {
                s::IsComparison::NoCompare
            };
            info.samplers.push(s::SamplerVar {
                name: name.to_owned(),
                slot: res_desc.BindPoint as core::SamplerSlot,
                ty: s::SamplerType(cmp, s::IsRect::NoRect),
                usage: usage,
            });
        }else {
            error!("Unsupported resource type {:?} for {}", res_desc.Type, name);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>collinear: fix error in fast method logic<commit_after><|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cmake;

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

static SHADERC_REPO: &'static str = "https://github.com/google/shaderc";
static GLSLANG_REPO: &'static str = "https://github.com/google/glslang";
static SPIRV_TOOLS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Tools";
static SPIRV_HEADERS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Headers";

fn git_clone_or_update(project: &str, url: &str, dir: &PathBuf) {
    if dir.as_path().exists() {
        let status = Command::new("git")
            .arg("pull")
            .current_dir(dir)
            .status()
            .expect("failed to execute git pull");
        if !status.success() {
            panic!("git pull {} failed", project)
        }
    } else {
        let status = Command::new("git")
            .args(&["clone", url, dir.to_str().unwrap()])
            .status()
            .expect("failed to execute git clone");
        if !status.success() {
            panic!("git clone {} failed", project)
        }
    }
}

#[cfg(windows)]
fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            // cmake-rs tries to be clever on Windows by injecting several
            // C/C++ flags, which causes problems. So I have to manually
            // define CMAKE_*_FLAGS_* here to suppress that.
            .define("CMAKE_C_FLAGS", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc")
            .build()
}

#[cfg(not(windows))]
fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            .build()
}

fn main() {
    if env::var("CARGO_FEATURE_BUILD_NATIVE_SHADERC").is_err() {
        println!("cargo:warning=requested to skip building native C++ shaderc");
        return
    }

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = Path::new(&manifest_dir).join("target");
    let shaderc_dir = Path::new(&target_dir).join("native-shaderc");
    let third_party_dir = Path::new(&shaderc_dir).join("third_party");
    let glslang_dir = Path::new(&third_party_dir).join("glslang");
    let spirv_tools_dir = Path::new(&third_party_dir).join("spirv-tools");
    let external_dir = Path::new(&spirv_tools_dir).join("external");
    let spirv_headers_dir = Path::new(&external_dir).join("spirv-headers");

    git_clone_or_update("shaderc", SHADERC_REPO, &shaderc_dir);
    git_clone_or_update("glslang", GLSLANG_REPO, &glslang_dir);
    git_clone_or_update("spirv-tools", SPIRV_TOOLS_REPO, &spirv_tools_dir);
    git_clone_or_update("spirv-headers", SPIRV_HEADERS_REPO, &spirv_headers_dir);

    let mut lib_path = build_shaderc(&shaderc_dir);
    lib_path.push("lib");

    println!("cargo:rustc-link-lib=static=shaderc_combined");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
}
<commit_msg>Remove Windows specific CMake configurations<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cmake;

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

static SHADERC_REPO: &'static str = "https://github.com/google/shaderc";
static GLSLANG_REPO: &'static str = "https://github.com/google/glslang";
static SPIRV_TOOLS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Tools";
static SPIRV_HEADERS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Headers";

fn git_clone_or_update(project: &str, url: &str, dir: &PathBuf) {
    if dir.as_path().exists() {
        let status = Command::new("git")
            .arg("pull")
            .current_dir(dir)
            .status()
            .expect("failed to execute git pull");
        if !status.success() {
            panic!("git pull {} failed", project)
        }
    } else {
        let status = Command::new("git")
            .args(&["clone", url, dir.to_str().unwrap()])
            .status()
            .expect("failed to execute git clone");
        if !status.success() {
            panic!("git clone {} failed", project)
        }
    }
}

fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            .build()
}

fn main() {
    if env::var("CARGO_FEATURE_BUILD_NATIVE_SHADERC").is_err() {
        println!("cargo:warning=requested to skip building native C++ shaderc");
        return
    }

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = Path::new(&manifest_dir).join("target");
    let shaderc_dir = Path::new(&target_dir).join("native-shaderc");
    let third_party_dir = Path::new(&shaderc_dir).join("third_party");
    let glslang_dir = Path::new(&third_party_dir).join("glslang");
    let spirv_tools_dir = Path::new(&third_party_dir).join("spirv-tools");
    let external_dir = Path::new(&spirv_tools_dir).join("external");
    let spirv_headers_dir = Path::new(&external_dir).join("spirv-headers");

    git_clone_or_update("shaderc", SHADERC_REPO, &shaderc_dir);
    git_clone_or_update("glslang", GLSLANG_REPO, &glslang_dir);
    git_clone_or_update("spirv-tools", SPIRV_TOOLS_REPO, &spirv_tools_dir);
    git_clone_or_update("spirv-headers", SPIRV_HEADERS_REPO, &spirv_headers_dir);

    let mut lib_path = build_shaderc(&shaderc_dir);
    lib_path.push("lib");

    println!("cargo:rustc-link-lib=static=shaderc_combined");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
}
<|endoftext|>


<commit_before>use helpers::*;
use core::mem;
use hil::{uart, Controller};
use hil::uart::Parity;
use dma::{DMAChannel, DMAClient};
use nvic;
use pm::{self, Clock, PBAClock};
use chip;

use process::AppSlice;

#[repr(C, packed)]
struct Registers {
    cr: u32,
    mr: u32,
    ier: u32,
    idr: u32,
    imr: u32,
    csr: u32,
    rhr: u32,
    thr: u32,
    brgr: u32, // 0x20
    rtor: u32,
    ttgr: u32,
    reserved0: [u32; 5],
    fidi: u32, // 0x40
    ner: u32,
    reserved1: u32,
    ifr: u32,
    man: u32,
    linmr: u32,
    linir: u32,
    linbrr: u32,
    wpmr: u32,
    wpsr: u32,
    version: u32
}

const SIZE: usize = 0x4000;
const BASE_ADDRESS: usize = 0x40024000;

#[derive(Copy,Clone)]
pub enum Location {
    USART0, USART1, USART2, USART3
}

pub struct USART {
    regs: *mut Registers,
    client: Option<&'static uart::Client>,
    clock: Clock,
    nvic: nvic::NvicIdx,
    dma: Option<&'static mut DMAChannel>,
}

pub struct USARTParams {
    //pub client: &'static Shared<uart::Client>,
    pub baud_rate: u32,
    pub data_bits: u8,
    pub parity: Parity
}

impl Controller for USART {
    type Config = USARTParams;

    fn configure(&self, params: USARTParams) {
     //   self.client = Some(params.client.borrow_mut());
        let chrl = ((params.data_bits - 1) & 0x3) as u32;
        let mode = 0 /* mode */
            | 0 << 4 /*USCLKS*/
            | chrl << 6 /* Character Length */
            | (params.parity as u32) << 9 /* Parity */
            | 0 << 12; /* Number of stop bits = 1 */;

        self.enable_clock();
        self.set_baud_rate(params.baud_rate);
        self.set_mode(mode);
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ttgr, 4);
        self.enable_rx_interrupts();
    }
}

pub static mut USART0 : USART =
    USART::new(Location::USART0, PBAClock::USART0, nvic::NvicIdx::USART0);
pub static mut USART1 : USART =
    USART::new(Location::USART1, PBAClock::USART1, nvic::NvicIdx::USART1);
pub static mut USART2 : USART =
    USART::new(Location::USART2, PBAClock::USART2, nvic::NvicIdx::USART2);
pub static mut USART3 : USART =
    USART::new(Location::USART3, PBAClock::USART3, nvic::NvicIdx::USART3);

impl USART {
    const fn new(location: Location, clock: PBAClock, nvic: nvic::NvicIdx)
            -> USART {
        USART {
            regs: (BASE_ADDRESS + (location as usize) * SIZE)
                as *mut Registers,
            clock: Clock::PBA(clock),
            nvic: nvic,
            dma: None,
            client: None,
        }
    }

    pub fn set_client<C: uart::Client>(&mut self, client: &'static C) {
        self.client = Some(client);
    }

    pub fn set_dma(&mut self, dma: &'static mut DMAChannel) {
        self.dma = Some(dma);
    }

    fn set_baud_rate(&self, baud_rate: u32) {
        let cd = 48000000 / (16 * baud_rate);
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.brgr, cd);
    }

    fn set_mode(&self, mode: u32) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.mr, mode);
    }

    fn enable_clock(&self) {
        unsafe {
            pm::enable_clock(self.clock);
        }
    }

    fn enable_nvic(&self) {
        unsafe {
            nvic::enable(self.nvic);
        }
    }

    fn disable_nvic(&self) {
        unsafe {
            nvic::disable(self.nvic);
        }
    }

    pub fn enable_rx_interrupts(&self) {
        self.enable_nvic();
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ier, 1 as u32);
    }

    pub fn enable_tx_interrupts(&mut self) {
        self.enable_nvic();
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ier, 2 as u32);
    }

    pub fn disable_rx_interrupts(&mut self) {
        self.disable_nvic();
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.idr, 1 as u32);
    }

    pub fn handle_interrupt(&mut self) {
        use hil::uart::UART;
        if self.rx_ready() {
            let regs : &Registers = unsafe { mem::transmute(self.regs) };
            let c = volatile_load(&regs.rhr) as u8;
            match self.client {
                Some(ref client) => {client.read_done(c)},
                None => {}
            }
        }
    }

    pub fn reset_rx(&mut self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 2);
    }
}

impl DMAClient for USART {
#[allow(unused_variables)]
    fn xfer_done(&mut self, pid: usize) {
        self.dma.as_mut().map(|dma| dma.disable());
        self.client.as_ref().map(|c| c.write_done() );
    }
}

impl uart::UART for USART {
    fn init(&mut self, params: uart::UARTParams) {
        let chrl = ((params.data_bits - 1) & 0x3) as u32;
        let mode = 0 /* mode */
            | 0 << 4 /*USCLKS*/
            | chrl << 6 /* Character Length */
            | (params.parity as u32) << 9 /* Parity */
            | 0 << 12; /* Number of stop bits = 1 */;

        self.enable_clock();
        self.set_baud_rate(params.baud_rate);
        self.set_mode(mode);
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ttgr, 4);
    }

    fn send_byte(&self, byte: u8) {
        while !self.tx_ready() {}
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.thr, byte as u32);
    }

    #[inline(never)]
    fn send_bytes<S>(&self, bytes: AppSlice<S, u8>) {
        self.dma.as_ref().map(|dma| {
            dma.enable();
            dma.do_xfer(21, bytes);
        });
    }

    fn rx_ready(&self) -> bool {
        let regs : &Registers = unsafe { mem::transmute(self.regs) };
        volatile_load(&regs.csr) & 0b1 != 0
    }

    fn tx_ready(&self) -> bool {
        let regs : &Registers = unsafe { mem::transmute(self.regs) };
        volatile_load(&regs.csr) & 0b10 != 0
    }

    fn read_byte(&self) -> u8 {
        while !self.rx_ready() {}
        let regs : &Registers = unsafe { mem::transmute(self.regs) };
        volatile_load(&regs.rhr) as u8
    }

    fn enable_rx(&self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 4);
    }

    fn disable_rx(&mut self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 5);
    }

    fn enable_tx(&self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 6);
    }

    fn disable_tx(&mut self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 7);
    }

}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn USART3_Handler() {
    use common::Queue;

    nvic::disable(nvic::NvicIdx::USART3);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::USART3);
}

<commit_msg>Use _ instead of allow(unused_variables)<commit_after>use helpers::*;
use core::mem;
use hil::{uart, Controller};
use hil::uart::Parity;
use dma::{DMAChannel, DMAClient};
use nvic;
use pm::{self, Clock, PBAClock};
use chip;

use process::AppSlice;

#[repr(C, packed)]
struct Registers {
    cr: u32,
    mr: u32,
    ier: u32,
    idr: u32,
    imr: u32,
    csr: u32,
    rhr: u32,
    thr: u32,
    brgr: u32, // 0x20
    rtor: u32,
    ttgr: u32,
    reserved0: [u32; 5],
    fidi: u32, // 0x40
    ner: u32,
    reserved1: u32,
    ifr: u32,
    man: u32,
    linmr: u32,
    linir: u32,
    linbrr: u32,
    wpmr: u32,
    wpsr: u32,
    version: u32
}

const SIZE: usize = 0x4000;
const BASE_ADDRESS: usize = 0x40024000;

#[derive(Copy,Clone)]
pub enum Location {
    USART0, USART1, USART2, USART3
}

pub struct USART {
    regs: *mut Registers,
    client: Option<&'static uart::Client>,
    clock: Clock,
    nvic: nvic::NvicIdx,
    dma: Option<&'static mut DMAChannel>,
}

pub struct USARTParams {
    //pub client: &'static Shared<uart::Client>,
    pub baud_rate: u32,
    pub data_bits: u8,
    pub parity: Parity
}

impl Controller for USART {
    type Config = USARTParams;

    fn configure(&self, params: USARTParams) {
     //   self.client = Some(params.client.borrow_mut());
        let chrl = ((params.data_bits - 1) & 0x3) as u32;
        let mode = 0 /* mode */
            | 0 << 4 /*USCLKS*/
            | chrl << 6 /* Character Length */
            | (params.parity as u32) << 9 /* Parity */
            | 0 << 12; /* Number of stop bits = 1 */;

        self.enable_clock();
        self.set_baud_rate(params.baud_rate);
        self.set_mode(mode);
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ttgr, 4);
        self.enable_rx_interrupts();
    }
}

pub static mut USART0 : USART =
    USART::new(Location::USART0, PBAClock::USART0, nvic::NvicIdx::USART0);
pub static mut USART1 : USART =
    USART::new(Location::USART1, PBAClock::USART1, nvic::NvicIdx::USART1);
pub static mut USART2 : USART =
    USART::new(Location::USART2, PBAClock::USART2, nvic::NvicIdx::USART2);
pub static mut USART3 : USART =
    USART::new(Location::USART3, PBAClock::USART3, nvic::NvicIdx::USART3);

impl USART {
    const fn new(location: Location, clock: PBAClock, nvic: nvic::NvicIdx)
            -> USART {
        USART {
            regs: (BASE_ADDRESS + (location as usize) * SIZE)
                as *mut Registers,
            clock: Clock::PBA(clock),
            nvic: nvic,
            dma: None,
            client: None,
        }
    }

    pub fn set_client<C: uart::Client>(&mut self, client: &'static C) {
        self.client = Some(client);
    }

    pub fn set_dma(&mut self, dma: &'static mut DMAChannel) {
        self.dma = Some(dma);
    }

    fn set_baud_rate(&self, baud_rate: u32) {
        let cd = 48000000 / (16 * baud_rate);
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.brgr, cd);
    }

    fn set_mode(&self, mode: u32) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.mr, mode);
    }

    fn enable_clock(&self) {
        unsafe {
            pm::enable_clock(self.clock);
        }
    }

    fn enable_nvic(&self) {
        unsafe {
            nvic::enable(self.nvic);
        }
    }

    fn disable_nvic(&self) {
        unsafe {
            nvic::disable(self.nvic);
        }
    }

    pub fn enable_rx_interrupts(&self) {
        self.enable_nvic();
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ier, 1 as u32);
    }

    pub fn enable_tx_interrupts(&mut self) {
        self.enable_nvic();
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ier, 2 as u32);
    }

    pub fn disable_rx_interrupts(&mut self) {
        self.disable_nvic();
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.idr, 1 as u32);
    }

    pub fn handle_interrupt(&mut self) {
        use hil::uart::UART;
        if self.rx_ready() {
            let regs : &Registers = unsafe { mem::transmute(self.regs) };
            let c = volatile_load(&regs.rhr) as u8;
            match self.client {
                Some(ref client) => {client.read_done(c)},
                None => {}
            }
        }
    }

    pub fn reset_rx(&mut self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 2);
    }
}

impl DMAClient for USART {
    fn xfer_done(&mut self, _pid: usize) {
        self.dma.as_mut().map(|dma| dma.disable());
        self.client.as_ref().map(|c| c.write_done() );
    }
}

impl uart::UART for USART {
    fn init(&mut self, params: uart::UARTParams) {
        let chrl = ((params.data_bits - 1) & 0x3) as u32;
        let mode = 0 /* mode */
            | 0 << 4 /*USCLKS*/
            | chrl << 6 /* Character Length */
            | (params.parity as u32) << 9 /* Parity */
            | 0 << 12; /* Number of stop bits = 1 */;

        self.enable_clock();
        self.set_baud_rate(params.baud_rate);
        self.set_mode(mode);
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.ttgr, 4);
    }

    fn send_byte(&self, byte: u8) {
        while !self.tx_ready() {}
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.thr, byte as u32);
    }

    #[inline(never)]
    fn send_bytes<S>(&self, bytes: AppSlice<S, u8>) {
        self.dma.as_ref().map(|dma| {
            dma.enable();
            dma.do_xfer(21, bytes);
        });
    }

    fn rx_ready(&self) -> bool {
        let regs : &Registers = unsafe { mem::transmute(self.regs) };
        volatile_load(&regs.csr) & 0b1 != 0
    }

    fn tx_ready(&self) -> bool {
        let regs : &Registers = unsafe { mem::transmute(self.regs) };
        volatile_load(&regs.csr) & 0b10 != 0
    }

    fn read_byte(&self) -> u8 {
        while !self.rx_ready() {}
        let regs : &Registers = unsafe { mem::transmute(self.regs) };
        volatile_load(&regs.rhr) as u8
    }

    fn enable_rx(&self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 4);
    }

    fn disable_rx(&mut self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 5);
    }

    fn enable_tx(&self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 6);
    }

    fn disable_tx(&mut self) {
        let regs : &mut Registers = unsafe { mem::transmute(self.regs) };
        volatile_store(&mut regs.cr, 1 << 7);
    }

}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn USART3_Handler() {
    use common::Queue;

    nvic::disable(nvic::NvicIdx::USART3);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::USART3);
}

<|endoftext|>


<commit_before><commit_msg>play with operator overloading in `Tensor`.<commit_after><|endoftext|>


<commit_before>extern crate glob;
extern crate prost_build;

fn main() {
    use glob::glob;

    prost_build::compile_protos(&["../common_protos/scaii.proto"], &["../common_protos"]).unwrap();

    // Make our protobuf file a reason to recompile
    // (See http://doc.crates.io/build-script.html for more info
    // on outputs)
    for entry in glob("../common_protos/*.rs") {
        println!("cargo:rerun-if-changed={}", path.display());
    }

    // Unfortunately, rerun-if-changed overrides Cargo's default handling, which
    // is to rerun if any of our files change, so we have to re-add all our source
    // files
    println!("cargo:rerun-if-changed=Cargo.toml");

    for entry in glob("src/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display())
        }
    }
}
<commit_msg>fixup! Add new protos to build script<commit_after>extern crate glob;
extern crate prost_build;

fn main() {
    use glob::glob;

    prost_build::compile_protos(&["../common_protos/scaii.proto"], &["../common_protos"]).unwrap();

    // Make our protobuf file a reason to recompile
    // (See http://doc.crates.io/build-script.html for more info
    // on outputs)
    for entry in glob("../common_protos/*.rs") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    // Unfortunately, rerun-if-changed overrides Cargo's default handling, which
    // is to rerun if any of our files change, so we have to re-add all our source
    // files
    println!("cargo:rerun-if-changed=Cargo.toml");

    for entry in glob("src/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display())
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate custom_derive;
#[macro_use]
extern crate derive_builder;

#[derive(Debug)]
struct Resolution {
    width: u32,
    height: u32,
}

impl Default for Resolution {
    fn default() -> Resolution {
        Resolution {
            width: 1920,
            height: 1080,
        }
    }
}

custom_derive! {
    #[derive(Debug, Default, Builder)]
    struct GameConfig {
        resolution: Resolution,
        save_dir: Option<String>,
        autosave: bool,
        fov: f32,
        render_distance: u32,
    }
}

fn main() {
    println!("24 Days of Rust vol. 2 - derive_builder");
    let mut conf = GameConfig::default();
    conf.save_dir("saves".to_string()).fov(70.0).render_distance(1000u32);
    println!("{:?}", conf);
}
<commit_msg>Fix derive_builder example.<commit_after>#[macro_use]
extern crate derive_builder;

#[derive(Clone, Debug)]
struct Resolution {
    width: u32,
    height: u32,
}

impl Default for Resolution {
    fn default() -> Resolution {
        Resolution {
            width: 1920,
            height: 1080,
        }
    }
}

#[derive(Debug, Default, Builder)]
#[builder(field(private), setter(into))]
struct GameConfig {
    #[builder(default)]
    resolution: Resolution,
    save_dir: Option<String>,
    #[builder(default)]
    autosave: bool,
    fov: f32,
    render_distance: u32,
}

fn main() {
    println!("24 Days of Rust vol. 2 - derive_builder");
    let conf = GameConfigBuilder::default()
        .save_dir("saves".to_string())
        .fov(70.0)
        .render_distance(1000u32)
        .build()
        .unwrap();
    println!("{:?}", conf);
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::process::exit;

use clap::ArgMatches;

use libimagdiary::diary::Diary;
use libimagdiary::diaryid::DiaryId;
use libimagdiary::error::DiaryErrorKind as DEK;
use libimagdiary::error::ResultExt;
use libimagentryedit::edit::Edit;
use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error_exit;
use libimagutil::warn_exit::warn_exit;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;

use util::get_diary_name;

pub fn create(rt: &Runtime) {
    let diaryname = get_diary_name(rt)
        .unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));

    let mut entry = create_entry(rt.store(), &diaryname, rt);

    let res = if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") {
        debug!("Not editing new diary entry");
        Ok(())
    } else {
        debug!("Editing new diary entry");
        entry.edit_content(rt)
            .chain_err(|| DEK::DiaryEditError)
    };

    if let Err(e) = res {
        trace_error_exit(&e, 1);
    } else {
        info!("Ok!");
    }
}

fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> {
    let create = rt.cli().subcommand_matches("create").unwrap();
    let entry  = if !create.is_present("timed") {
        debug!("Creating non-timed entry");
        diary.new_entry_today(diaryname)
    } else {
        let id = create_id_from_clispec(&create, &diaryname);
        diary.retrieve(id).chain_err(|| DEK::StoreReadError)
    };

    match entry {
        Err(e) => trace_error_exit(&e, 1),
        Ok(e) => {
            debug!("Created: {}", e.get_location());
            e
        }
    }
}

fn create_id_from_clispec(create: &ArgMatches, diaryname: &str) -> DiaryId {
    use std::str::FromStr;

    let get_hourly_id = |create: &ArgMatches| -> DiaryId {
        let time = DiaryId::now(String::from(diaryname));
        let hr = create
            .value_of("hour")
            .map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
            .and_then(|s| {
                FromStr::from_str(s)
                    .map_err(|_| warn!("Could not parse hour: '{}'", s))
                    .ok()
            })
            .unwrap_or(time.hour());

        time.with_hour(hr)
    };

    match create.value_of("timed") {
        Some("h") | Some("hourly") => {
            debug!("Creating hourly-timed entry");
            get_hourly_id(create)
        },

        Some("m") | Some("minutely") => {
            let time = get_hourly_id(create);
            let min = create
                .value_of("minute")
                .map(|m| { debug!("minute = {:?}", m); m })
                .and_then(|s| {
                    FromStr::from_str(s)
                        .map_err(|_| warn!("Could not parse minute: '{}'", s))
                        .ok()
                })
                .unwrap_or(time.minute());

            time.with_minute(min)
        },

        Some(_) => {
            warn!("Timed creation failed: Unknown spec '{}'",
                  create.value_of("timed").unwrap());
            exit(1);
        },

        None => warn_exit("Unexpected error, cannot continue", 1)
    }
}

<commit_msg>Change create() to check config and commandline whether entry should be created timed or not<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use clap::ArgMatches;

use libimagdiary::diary::Diary;
use libimagdiary::diaryid::DiaryId;
use libimagdiary::error::DiaryErrorKind as DEK;
use libimagdiary::error::ResultExt;
use libimagentryedit::edit::Edit;
use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error_exit;
use libimagerror::trace::MapErrTrace;
use libimagutil::warn_exit::warn_exit;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;

use util::get_diary_name;
use util::get_diary_timed_config;
use util::Timed;

pub fn create(rt: &Runtime) {
    let diaryname = get_diary_name(rt)
        .unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));

    let mut entry = create_entry(rt.store(), &diaryname, rt);

    let res = if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") {
        debug!("Not editing new diary entry");
        Ok(())
    } else {
        debug!("Editing new diary entry");
        entry.edit_content(rt)
            .chain_err(|| DEK::DiaryEditError)
    };

    if let Err(e) = res {
        trace_error_exit(&e, 1);
    } else {
        info!("Ok!");
    }
}

fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> {
    use util::parse_timed_string;

    let create = rt.cli().subcommand_matches("create").unwrap();

    let create_timed = create.value_of("timed")
        .map(|t| parse_timed_string(t, diaryname).map_err_trace_exit(1).unwrap())
        .map(Some)
        .unwrap_or_else(|| match get_diary_timed_config(rt, diaryname) {
            Err(e)      => trace_error_exit(&e, 1),
            Ok(Some(t)) => Some(t),
            Ok(None)    => {
                warn!("Missing config: 'diary.diaries.{}.timed'", diaryname);
                warn!("Assuming 'false'");
                None
            }
        });

    let entry = match create_timed {
        Some(timed) => {
            let id = create_id_from_clispec(&create, &diaryname, timed);
            diary.retrieve(id).chain_err(|| DEK::StoreReadError)
        },

        None => {
            debug!("Creating non-timed entry");
            diary.new_entry_today(diaryname)
        }
    };

    match entry {
        Err(e) => trace_error_exit(&e, 1),
        Ok(e) => {
            debug!("Created: {}", e.get_location());
            e
        }
    }
}

fn create_id_from_clispec(create: &ArgMatches, diaryname: &str, timed_type: Timed) -> DiaryId {
    use std::str::FromStr;

    let get_hourly_id = |create: &ArgMatches| -> DiaryId {
        let time = DiaryId::now(String::from(diaryname));
        let hr = create
            .value_of("hour")
            .map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
            .and_then(|s| {
                FromStr::from_str(s)
                    .map_err(|_| warn!("Could not parse hour: '{}'", s))
                    .ok()
            })
            .unwrap_or(time.hour());

        time.with_hour(hr)
    };

    match timed_type {
        Timed::Hourly => {
            debug!("Creating hourly-timed entry");
            get_hourly_id(create)
        },

        Timed::Minutely => {
            let time = get_hourly_id(create);
            let min = create
                .value_of("minute")
                .map(|m| { debug!("minute = {:?}", m); m })
                .and_then(|s| {
                    FromStr::from_str(s)
                        .map_err(|_| warn!("Could not parse minute: '{}'", s))
                        .ok()
                })
                .unwrap_or(time.minute());

            time.with_minute(min)
        },
    }
}

<|endoftext|>


<commit_before>extern crate "rust-hl-lua" as lua;

#[test]
fn readwrite() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::AsLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);
    let _: Foo = lua.get("a").unwrap();
}

#[test]
fn destructor_called() {
    use std::sync::{Arc, Mutex};

    let called = Arc::new(Mutex::new(false));

    struct Foo {
        called: Arc<Mutex<bool>>
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            let mut called = self.called.lock().unwrap();
            (*called) = true;
        }
    }

    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }

    {
        let mut lua = lua::Lua::new();
        lua.set("a", Foo{called: called.clone()});
    }

    let locked = called.lock().unwrap();
    assert!(*locked);
}

#[test]
fn type_check() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::AsLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    #[deriving(Clone)]
    struct Bar;
    impl<L: lua::AsLua> lua::Push<L> for Bar {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::AsLua> lua::CopyRead<L> for Bar {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Bar> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: Option<Bar> = lua.get("a");
    assert!(x.is_none())
}

#[test]
fn metatables() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |table| {
                table.set("__index".to_string(), vec!(
                    ("test".to_string(), || 5i)
                ));
            })
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: int = lua.execute("return a.test()").unwrap();
    assert_eq!(x, 5);
}
<commit_msg>Fix userdata tests<commit_after>extern crate "rust-hl-lua" as lua;

#[test]
fn readwrite() {
    #[derive(Clone)]
    struct Foo;
    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::AsLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);
    let _: Foo = lua.get("a").unwrap();
}

#[test]
fn destructor_called() {
    use std::sync::{Arc, Mutex};

    let called = Arc::new(Mutex::new(false));

    struct Foo {
        called: Arc<Mutex<bool>>
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            let mut called = self.called.lock().unwrap();
            (*called) = true;
        }
    }

    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }

    {
        let mut lua = lua::Lua::new();
        lua.set("a", Foo{called: called.clone()});
    }

    let locked = called.lock().unwrap();
    assert!(*locked);
}

#[test]
fn type_check() {
    #[derive(Clone)]
    struct Foo;
    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::AsLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    #[derive(Clone)]
    struct Bar;
    impl<L: lua::AsLua> lua::Push<L> for Bar {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::AsLua> lua::CopyRead<L> for Bar {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Bar> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: Option<Bar> = lua.get("a");
    assert!(x.is_none())
}

#[test]
fn metatables() {
    #[derive(Clone)]
    struct Foo;
    impl<L: lua::AsLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |table| {
                table.set("__index".to_string(), vec!(
                    ("test".to_string(), || 5i)
                ));
            })
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: int = lua.execute("return a.test()").unwrap();
    assert_eq!(x, 5);
}
<|endoftext|>


<commit_before>//! Tools to define Rust components compatible with the COM protocol.
//!
//! Intercom provides attributes to automatically derive `extern` compatible
//! functions for Rust methods. These functions are compatible with COM binary
//! interface standard, which allows them to be used from any language that
//! supports COM.
//!
//! # Examples
//!
//! A basic example of a calculator type exposed as a COM object.
//!
//! ```
//! use intercom::{com_library, com_class, com_interface, ComResult};
//!
//! // Define COM classes to expose from this library.
//! com_library!(class Calculator);
//!
//! // Define the COM class and the interfaces it implements.
//! #[com_class(Self)]
//! #[derive(Default)]
//! struct Calculator;
//!
//! // Define the implementation for the class. The COM interface is defined
//! // implicitly by the `impl`.
//! #[com_interface]
//! impl Calculator {
//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
//! }
//! # // Without 'main()' doctests wraps the whole thing into a function,
//! # // which would end up expanding com_library!(..) into a statement.
//! # // And proc macros into statements are not allowed.
//! # //
//! # // In addition to that, if we just have `fn main()` followed by open
//! # // brace _anywhere_ in this doctest (yes, including these comments),
//! # // clippy would discover that and yell at us for "needless doctest main".
//! # // Allowing that with a specific #[allow(..)] attribute is impossible
//! # // since this is crate-level documentation.
//! # //
//! # // Fortunately we can hide this from clippy by specifying the (empty)
//! # // return type.
//! # fn main() -> () { }
//! ```
//!
//! The above library can be used for example from C# in the following manner.
//!
//! ```csharp
//! void Main()
//! {
//!     var calculator = new CalculatorLib.Calculator();
//!     Console.WriteLine( calculator.Add( 1, 2 ) );
//! }
//! ```

#![crate_type = "dylib"]
#![allow(clippy::match_bool)]

extern crate self as intercom;

#[cfg(not(windows))]
extern crate libc;

extern crate intercom_attributes;
pub use intercom_attributes::*;

#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
#[macro_use]
extern crate failure;

#[cfg(feature = "log")]
extern crate log;

pub mod prelude;

mod classfactory;
pub use crate::classfactory::*;
mod combox;
pub use crate::combox::*;
mod comrc;
pub use crate::comrc::*;
mod comitf;
pub use crate::comitf::*;
mod strings;
pub use crate::strings::*;
mod guid;
pub use crate::guid::GUID;
pub mod error;
pub use crate::error::{load_error, store_error, ComError, ErrorValue};
pub mod alloc;
pub mod interfaces;
pub mod runtime;
mod variant;
pub use crate::variant::{Variant, VariantError};
pub mod type_system;
pub mod typelib;
pub use type_system::ForeignType;
pub mod attributes;
pub mod logging;

#[cfg(windows)]
pub mod registry;

// No-ops on non-windows platforms.
#[cfg(not(windows))]
pub mod registry
{
    /// Registers a type library.
    pub fn register(dll: HANDLE, lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }

    /// Unregisters a type library.
    pub fn unregister(dll: HANDLE, lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }
}

com_module!(
    class intercom::alloc::Allocator,
    class intercom::error::ErrorStore,
);

/// Raw COM pointer type.
/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

pub mod raw
{
    use std::marker::PhantomData;
    use std::os::raw::c_void;
    use std::ptr::NonNull;

    pub use crate::error::raw::*;
    pub use crate::type_system::{ForeignType, TypeSystem};
    pub use crate::variant::raw::*;

    pub type RawComPtr = *mut c_void;

    #[derive(Clone, Copy, intercom_attributes::ExternInput, intercom_attributes::ForeignType)]
    #[repr(transparent)]
    pub struct InBSTR(pub *const u16);

    #[derive(
        Clone,
        Copy,
        intercom_attributes::ExternInput,
        intercom_attributes::ExternOutput,
        intercom_attributes::ForeignType,
    )]
    #[repr(transparent)]
    pub struct OutBSTR(pub *mut u16);

    pub type InCStr = *const std::os::raw::c_char;
    pub type OutCStr = *mut std::os::raw::c_char;

    #[repr(transparent)]
    #[derive(PartialEq, Eq)]
    pub struct InterfacePtr<TS: TypeSystem, I: ?Sized>
    {
        pub ptr: NonNull<c_void>,
        phantom_itf: PhantomData<I>,
        phantom_ts: PhantomData<TS>,
    }

    impl<TS: TypeSystem, I: ?Sized> Clone for InterfacePtr<TS, I>
    {
        fn clone(&self) -> Self
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: ?Sized> Copy for InterfacePtr<TS, I> {}

    impl<TS: TypeSystem, I: ?Sized> std::fmt::Debug for InterfacePtr<TS, I>
    {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
        {
            write!(f, "InterfacePtr({:?})", self.ptr)
        }
    }

    impl<TS: TypeSystem, I: ?Sized> InterfacePtr<TS, I>
    {
        /// # Safety
        ///
        /// The raw `ptr` must represent the correct type system and interface.
        pub unsafe fn new(ptr: RawComPtr) -> Option<InterfacePtr<TS, I>>
        {
            let ptr = NonNull::new(ptr);
            ptr.map(|ptr| InterfacePtr {
                ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            })
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> InterfacePtr<TS, I>
    {
        pub fn as_unknown(self) -> InterfacePtr<TS, dyn crate::IUnknown>
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> ForeignType
        for Option<InterfacePtr<TS, I>>
    where
        I: ForeignType,
    {
        /// The name of the type.
        fn type_name() -> &'static str
        {
            <I as ForeignType>::type_name()
        }
        fn indirection_level() -> u32
        {
            <I as ForeignType>::indirection_level() + 1
        }
    }
}

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory: GUID = GUID {
    data1: 0x0000_0001,
    data2: 0x0000,
    data3: 0x0000,
    data4: [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46],
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo: GUID = GUID {
    data1: 0x1CF2_B120,
    data2: 0x547D,
    data3: 0x101B,
    data4: [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19],
};

pub use crate::interfaces::IUnknown;
// pub use crate::interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;

pub use crate::interfaces::ISupportErrorInfo;
// pub use crate::interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type ComResult<A> = Result<A, ComError>;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type RawComResult<A> = Result<A, raw::HRESULT>;
<commit_msg>Fix Linux build<commit_after>//! Tools to define Rust components compatible with the COM protocol.
//!
//! Intercom provides attributes to automatically derive `extern` compatible
//! functions for Rust methods. These functions are compatible with COM binary
//! interface standard, which allows them to be used from any language that
//! supports COM.
//!
//! # Examples
//!
//! A basic example of a calculator type exposed as a COM object.
//!
//! ```
//! use intercom::{com_library, com_class, com_interface, ComResult};
//!
//! // Define COM classes to expose from this library.
//! com_library!(class Calculator);
//!
//! // Define the COM class and the interfaces it implements.
//! #[com_class(Self)]
//! #[derive(Default)]
//! struct Calculator;
//!
//! // Define the implementation for the class. The COM interface is defined
//! // implicitly by the `impl`.
//! #[com_interface]
//! impl Calculator {
//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
//! }
//! # // Without 'main()' doctests wraps the whole thing into a function,
//! # // which would end up expanding com_library!(..) into a statement.
//! # // And proc macros into statements are not allowed.
//! # //
//! # // In addition to that, if we just have `fn main()` followed by open
//! # // brace _anywhere_ in this doctest (yes, including these comments),
//! # // clippy would discover that and yell at us for "needless doctest main".
//! # // Allowing that with a specific #[allow(..)] attribute is impossible
//! # // since this is crate-level documentation.
//! # //
//! # // Fortunately we can hide this from clippy by specifying the (empty)
//! # // return type.
//! # fn main() -> () { }
//! ```
//!
//! The above library can be used for example from C# in the following manner.
//!
//! ```csharp
//! void Main()
//! {
//!     var calculator = new CalculatorLib.Calculator();
//!     Console.WriteLine( calculator.Add( 1, 2 ) );
//! }
//! ```

#![crate_type = "dylib"]
#![allow(clippy::match_bool)]

extern crate self as intercom;

#[cfg(not(windows))]
extern crate libc;

extern crate intercom_attributes;
pub use intercom_attributes::*;

#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
#[macro_use]
extern crate failure;

#[cfg(feature = "log")]
extern crate log;

pub mod prelude;

mod classfactory;
pub use crate::classfactory::*;
mod combox;
pub use crate::combox::*;
mod comrc;
pub use crate::comrc::*;
mod comitf;
pub use crate::comitf::*;
mod strings;
pub use crate::strings::*;
mod guid;
pub use crate::guid::GUID;
pub mod error;
pub use crate::error::{load_error, store_error, ComError, ErrorValue};
pub mod alloc;
pub mod interfaces;
pub mod runtime;
mod variant;
pub use crate::variant::{Variant, VariantError};
pub mod type_system;
pub mod typelib;
pub use type_system::ForeignType;
pub mod attributes;
pub mod logging;

#[cfg(windows)]
pub mod registry;

// No-ops on non-windows platforms.
#[cfg(not(windows))]
pub mod registry
{
    use crate::typelib::TypeLib;
    use crate::raw::HRESULT;

    type HANDLE = *mut std::os::raw::c_void;

    /// Registers a type library.
    pub fn register(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }

    /// Unregisters a type library.
    pub fn unregister(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }
}

com_module!(
    class intercom::alloc::Allocator,
    class intercom::error::ErrorStore,
);

/// Raw COM pointer type.
/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

pub mod raw
{
    use std::marker::PhantomData;
    use std::os::raw::c_void;
    use std::ptr::NonNull;

    pub use crate::error::raw::*;
    pub use crate::type_system::{ForeignType, TypeSystem};
    pub use crate::variant::raw::*;

    pub type RawComPtr = *mut c_void;

    #[derive(Clone, Copy, intercom_attributes::ExternInput, intercom_attributes::ForeignType)]
    #[repr(transparent)]
    pub struct InBSTR(pub *const u16);

    #[derive(
        Clone,
        Copy,
        intercom_attributes::ExternInput,
        intercom_attributes::ExternOutput,
        intercom_attributes::ForeignType,
    )]
    #[repr(transparent)]
    pub struct OutBSTR(pub *mut u16);

    pub type InCStr = *const std::os::raw::c_char;
    pub type OutCStr = *mut std::os::raw::c_char;

    #[repr(transparent)]
    #[derive(PartialEq, Eq)]
    pub struct InterfacePtr<TS: TypeSystem, I: ?Sized>
    {
        pub ptr: NonNull<c_void>,
        phantom_itf: PhantomData<I>,
        phantom_ts: PhantomData<TS>,
    }

    impl<TS: TypeSystem, I: ?Sized> Clone for InterfacePtr<TS, I>
    {
        fn clone(&self) -> Self
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: ?Sized> Copy for InterfacePtr<TS, I> {}

    impl<TS: TypeSystem, I: ?Sized> std::fmt::Debug for InterfacePtr<TS, I>
    {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
        {
            write!(f, "InterfacePtr({:?})", self.ptr)
        }
    }

    impl<TS: TypeSystem, I: ?Sized> InterfacePtr<TS, I>
    {
        /// # Safety
        ///
        /// The raw `ptr` must represent the correct type system and interface.
        pub unsafe fn new(ptr: RawComPtr) -> Option<InterfacePtr<TS, I>>
        {
            let ptr = NonNull::new(ptr);
            ptr.map(|ptr| InterfacePtr {
                ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            })
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> InterfacePtr<TS, I>
    {
        pub fn as_unknown(self) -> InterfacePtr<TS, dyn crate::IUnknown>
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> ForeignType
        for Option<InterfacePtr<TS, I>>
    where
        I: ForeignType,
    {
        /// The name of the type.
        fn type_name() -> &'static str
        {
            <I as ForeignType>::type_name()
        }
        fn indirection_level() -> u32
        {
            <I as ForeignType>::indirection_level() + 1
        }
    }
}

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory: GUID = GUID {
    data1: 0x0000_0001,
    data2: 0x0000,
    data3: 0x0000,
    data4: [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46],
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo: GUID = GUID {
    data1: 0x1CF2_B120,
    data2: 0x547D,
    data3: 0x101B,
    data4: [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19],
};

pub use crate::interfaces::IUnknown;
// pub use crate::interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;

pub use crate::interfaces::ISupportErrorInfo;
// pub use crate::interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type ComResult<A> = Result<A, ComError>;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type RawComResult<A> = Result<A, raw::HRESULT>;
<|endoftext|>


<commit_before>/// Entity name and appearance.
#[deriving(Clone, Show, Encodable, Decodable)]
pub struct Desc {
    pub name: String,
    pub icon: uint,
}

impl Desc {
    pub fn new(name: String, icon: uint) -> Desc {
        Desc {
            name: name,
            icon: icon,
        }
    }
}
<commit_msg>Add color field to Desc component<commit_after>use calx::Rgb;

/// Entity name and appearance.
#[deriving(Clone, Show, Encodable, Decodable)]
pub struct Desc {
    pub name: String,
    pub icon: uint,
    pub color: Rgb,
}

impl Desc {
    pub fn new(name: String, icon: uint, color: Rgb) -> Desc {
        Desc {
            name: name,
            icon: icon,
            color: color,
        }
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Tests for ioreg! syntax extension

#![feature(core, plugin)]
#![plugin(ioreg)]

extern crate volatile_cell;

#[cfg(test)]
mod test {
  use std::mem::{transmute, zeroed};
  use volatile_cell::VolatileCell;

  fn get_value<'a, T>(v: &'a T, offset: usize) -> u32 {
    unsafe {
      let ptr: *const u32 = transmute(v);
      *(ptr.offset(offset as isize))
    }
  }

  fn zeroed_safe<T: Copy>() -> T {
    unsafe {
      return zeroed();
    }
  }

  ioregs!(BASIC_TEST @ 0 = {
    0x0 => reg32 reg1 {
      0      => field1,
      1..3   => field2,
      16..24 => field3,
      25     => field4: set_to_clear,
    }
    0x4 => reg32 reg2 {
      0      => field1,
    }
    0x8 => reg32 wo_reg {
      0..15  => field1: wo,
      16..31 => field2: wo,
    }
  });

  #[test]
  fn round_trip_simple_field_values_1() {
    let test: BASIC_TEST = zeroed_safe();

    test.reg1.set_field1(true);
    assert_eq!(test.reg1.field1(), true);
    assert_eq!(get_value(&test, 0), 1);
    assert_eq!(get_value(&test, 1), 0);
  }

  #[test]
  fn round_trip_simple_field_values_2() {
    let test: BASIC_TEST = zeroed_safe();

    test.reg1.set_field3(0xde);
    assert_eq!(test.reg1.field3(), 0xde);
    assert_eq!(get_value(&test, 0), 0xde<<16);
  }

  #[test]
  fn set_set_to_clear_fields() {
    let test: BASIC_TEST = zeroed_safe();

    test.reg1.clear_field4();
    assert_eq!(get_value(&test, 0), 1<<25);
  }

  #[test]
  fn no_read_writeonly_registers() {
    let test: BASIC_TEST = zeroed_safe();

    test.wo_reg.set_field1(0xdead);
    assert_eq!(get_value(&test, 2), 0xdead);
    test.wo_reg.set_field2(0xdead);
    assert_eq!(get_value(&test, 2), 0xdead<<16);
  }

  /*
     describe!(
     before_each {
     let test: BASIC_TEST = zeroed_safe();
     }

     it "can round_trip simple field values 1" {
     test.reg1.set_field1(true);
     assert_eq!(test.reg1.field1(), true);
     assert_eq!(get_value(&test, 0), 1);
     assert_eq!(get_value(&test, 1), 0);
     }

     it "can round trip simple field values 2" {
     test.reg1.set_field3(0xde);
     assert_eq!(test.reg1.field3(), 0xde);
     assert_eq!(get_value(&test, 0), 0xde<<16);
     }

     it "sets set_to_clear fields" {
     test.reg1.clear_field4();
     assert_eq!(get_value(&test, 0), 1<<25);
     }

     it "does not read from writeonly registers" {
     test.wo_reg.set_field1(0xdead);
     assert_eq!(get_value(&test, 2), 0xdead);
     test.wo_reg.set_field2(0xdead);
     assert_eq!(get_value(&test, 2), 0xdead<<16);
     }
     );
     */

  ioregs!(GROUP_TEST @ 0 = {
    0x0 => group regs[5] {
      0x0 => reg32 reg1 {
        0..31 => field1
      }
      0x4 => reg32 reg2 {
        0..31 => field2
      }
    }
  });

  #[test]
  fn sets_groups_correctly() {
    let test: GROUP_TEST = zeroed_safe();
    test.regs[0].reg1.set_field1(0xdeadbeef);
    assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef);
    assert_eq!(get_value(&test, 0), 0xdeadbeef);
    for i in 1..10 {
      assert_eq!(get_value(&test, i), 0);
    }

    test.regs[2].reg2.set_field2(0xfeedbeef);
    assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef);
    assert_eq!(get_value(&test, 5), 0xfeedbeef);
  }

  /*
     describe!(
     before_each {
     let test: GROUP_TEST = zeroed_safe();
     }

     it "sets groups correctly" {
     test.regs[0].reg1.set_field1(0xdeadbeef);
     assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef);
     assert_eq!(get_value(&test, 0), 0xdeadbeef);
     for i in range(1, 10) {
     assert_eq!(get_value(&test, i), 0);
     }

     test.regs[2].reg2.set_field2(0xfeedbeef);
     assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef);
     assert_eq!(get_value(&test, 5), 0xfeedbeef);
     }
     );
     */

  ioregs!(FIELD_ARRAY_TEST @ 0 = {
    0x0 => reg32 reg1 {
      0..31 => field[16]
    }
  });

  #[test]
  fn sets_field_arrays_correctly() {
    let test: FIELD_ARRAY_TEST = zeroed_safe();
    test.reg1.set_field(0, 1);
    assert_eq!(test.reg1.field(0), 1);
    assert_eq!(get_value(&test, 0), 0x1);

    test.reg1.set_field(4, 3);
    assert_eq!(test.reg1.field(4), 3);
    assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8);
  }

  /*
     describe!(
     before_each {
     let test: FIELD_ARRAY_TEST = zeroed_safe();
     }

     it "sets field arrays correctly" {
     test.reg1.set_field(0, 1);
     assert_eq!(test.reg1.field(0), 1);
     assert_eq!(get_value(&test, 0), 0x1);

     test.reg1.set_field(4, 3);
     assert_eq!(test.reg1.field(4), 3);
     assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8);
     }
     );
     */

  ioregs!(GAP_TEST @ 0 = {
    0x0 => reg32 reg1 {
      0..31 => field,
    }
    0x10 => reg32 reg2 {
      0..31 => field,
    }
    0x14 => reg32 reg3 {
      0..31 => field,
    }
    0x20 => reg32 reg4 {
      0..31 => field,
    }
  });

  #[test]
  fn has_zero_base_offset() {
    let test: GAP_TEST = zeroed_safe();
    let base = &test as *const GAP_TEST;
    let addr = &test.reg1 as *const GAP_TEST_reg1;
    assert_eq!(addr as usize - base as usize, 0x0);
  }

  #[test]
  fn computes_first_gap() {
    let test: GAP_TEST = zeroed_safe();
    let base = &test as *const GAP_TEST;
    let addr = &test.reg2 as *const GAP_TEST_reg2;
    assert_eq!(addr as usize - base as usize, 0x10);
  }

  #[test]
  fn computes_second_gap() {
    let test: GAP_TEST = zeroed_safe();
    let base = &test as *const GAP_TEST;
    let addr = &test.reg4 as *const GAP_TEST_reg4;
    assert_eq!(addr as usize - base as usize, 0x20);
  }

  /*
     describe!(
     before_each {
     let test: GAP_TEST = zeroed_safe();
     let base = &test as *const GAP_TEST;
     }
     it "has zero base offset" {
     let addr = &test.reg1 as *const GAP_TEST_reg1;
     assert_eq!(addr as usize - base as usize, 0x0);
     }
     it "computes the correct first gap" {
     let addr = &test.reg2 as *const GAP_TEST_reg2;
     assert_eq!(addr as usize - base as usize, 0x10);
     }
     it "computes the correct second gap" {
     let addr = &test.reg4 as *const GAP_TEST_reg4;
     assert_eq!(addr as usize - base as usize, 0x20);
     }
     );
     */

  ioregs!(MULTI_TEST @ 0 = {
    0x100 => reg32 reg1[8] {
      0..31 => field[32],
    }
  });

  #[test]
  fn multi_ok() {
    let test: MULTI_TEST = zeroed_safe();
    test.reg1[0].set_field(0, true);
    assert_eq!(test.reg1[0].field(0), true);
  }
}
<commit_msg>ioreg tests use std, so they still need to explicitly import core<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Tests for ioreg! syntax extension

#![feature(core, plugin)]
#![plugin(ioreg)]

extern crate volatile_cell;
extern crate core;

#[cfg(test)]
mod test {
  use std::mem::{transmute, zeroed};
  use volatile_cell::VolatileCell;

  fn get_value<'a, T>(v: &'a T, offset: usize) -> u32 {
    unsafe {
      let ptr: *const u32 = transmute(v);
      *(ptr.offset(offset as isize))
    }
  }

  fn zeroed_safe<T: Copy>() -> T {
    unsafe {
      return zeroed();
    }
  }

  ioregs!(BASIC_TEST @ 0 = {
    0x0 => reg32 reg1 {
      0      => field1,
      1..3   => field2,
      16..24 => field3,
      25     => field4: set_to_clear,
    }
    0x4 => reg32 reg2 {
      0      => field1,
    }
    0x8 => reg32 wo_reg {
      0..15  => field1: wo,
      16..31 => field2: wo,
    }
  });

  #[test]
  fn round_trip_simple_field_values_1() {
    let test: BASIC_TEST = zeroed_safe();

    test.reg1.set_field1(true);
    assert_eq!(test.reg1.field1(), true);
    assert_eq!(get_value(&test, 0), 1);
    assert_eq!(get_value(&test, 1), 0);
  }

  #[test]
  fn round_trip_simple_field_values_2() {
    let test: BASIC_TEST = zeroed_safe();

    test.reg1.set_field3(0xde);
    assert_eq!(test.reg1.field3(), 0xde);
    assert_eq!(get_value(&test, 0), 0xde<<16);
  }

  #[test]
  fn set_set_to_clear_fields() {
    let test: BASIC_TEST = zeroed_safe();

    test.reg1.clear_field4();
    assert_eq!(get_value(&test, 0), 1<<25);
  }

  #[test]
  fn no_read_writeonly_registers() {
    let test: BASIC_TEST = zeroed_safe();

    test.wo_reg.set_field1(0xdead);
    assert_eq!(get_value(&test, 2), 0xdead);
    test.wo_reg.set_field2(0xdead);
    assert_eq!(get_value(&test, 2), 0xdead<<16);
  }

  /*
     describe!(
     before_each {
     let test: BASIC_TEST = zeroed_safe();
     }

     it "can round_trip simple field values 1" {
     test.reg1.set_field1(true);
     assert_eq!(test.reg1.field1(), true);
     assert_eq!(get_value(&test, 0), 1);
     assert_eq!(get_value(&test, 1), 0);
     }

     it "can round trip simple field values 2" {
     test.reg1.set_field3(0xde);
     assert_eq!(test.reg1.field3(), 0xde);
     assert_eq!(get_value(&test, 0), 0xde<<16);
     }

     it "sets set_to_clear fields" {
     test.reg1.clear_field4();
     assert_eq!(get_value(&test, 0), 1<<25);
     }

     it "does not read from writeonly registers" {
     test.wo_reg.set_field1(0xdead);
     assert_eq!(get_value(&test, 2), 0xdead);
     test.wo_reg.set_field2(0xdead);
     assert_eq!(get_value(&test, 2), 0xdead<<16);
     }
     );
     */

  ioregs!(GROUP_TEST @ 0 = {
    0x0 => group regs[5] {
      0x0 => reg32 reg1 {
        0..31 => field1
      }
      0x4 => reg32 reg2 {
        0..31 => field2
      }
    }
  });

  #[test]
  fn sets_groups_correctly() {
    let test: GROUP_TEST = zeroed_safe();
    test.regs[0].reg1.set_field1(0xdeadbeef);
    assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef);
    assert_eq!(get_value(&test, 0), 0xdeadbeef);
    for i in 1..10 {
      assert_eq!(get_value(&test, i), 0);
    }

    test.regs[2].reg2.set_field2(0xfeedbeef);
    assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef);
    assert_eq!(get_value(&test, 5), 0xfeedbeef);
  }

  /*
     describe!(
     before_each {
     let test: GROUP_TEST = zeroed_safe();
     }

     it "sets groups correctly" {
     test.regs[0].reg1.set_field1(0xdeadbeef);
     assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef);
     assert_eq!(get_value(&test, 0), 0xdeadbeef);
     for i in range(1, 10) {
     assert_eq!(get_value(&test, i), 0);
     }

     test.regs[2].reg2.set_field2(0xfeedbeef);
     assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef);
     assert_eq!(get_value(&test, 5), 0xfeedbeef);
     }
     );
     */

  ioregs!(FIELD_ARRAY_TEST @ 0 = {
    0x0 => reg32 reg1 {
      0..31 => field[16]
    }
  });

  #[test]
  fn sets_field_arrays_correctly() {
    let test: FIELD_ARRAY_TEST = zeroed_safe();
    test.reg1.set_field(0, 1);
    assert_eq!(test.reg1.field(0), 1);
    assert_eq!(get_value(&test, 0), 0x1);

    test.reg1.set_field(4, 3);
    assert_eq!(test.reg1.field(4), 3);
    assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8);
  }

  /*
     describe!(
     before_each {
     let test: FIELD_ARRAY_TEST = zeroed_safe();
     }

     it "sets field arrays correctly" {
     test.reg1.set_field(0, 1);
     assert_eq!(test.reg1.field(0), 1);
     assert_eq!(get_value(&test, 0), 0x1);

     test.reg1.set_field(4, 3);
     assert_eq!(test.reg1.field(4), 3);
     assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8);
     }
     );
     */

  ioregs!(GAP_TEST @ 0 = {
    0x0 => reg32 reg1 {
      0..31 => field,
    }
    0x10 => reg32 reg2 {
      0..31 => field,
    }
    0x14 => reg32 reg3 {
      0..31 => field,
    }
    0x20 => reg32 reg4 {
      0..31 => field,
    }
  });

  #[test]
  fn has_zero_base_offset() {
    let test: GAP_TEST = zeroed_safe();
    let base = &test as *const GAP_TEST;
    let addr = &test.reg1 as *const GAP_TEST_reg1;
    assert_eq!(addr as usize - base as usize, 0x0);
  }

  #[test]
  fn computes_first_gap() {
    let test: GAP_TEST = zeroed_safe();
    let base = &test as *const GAP_TEST;
    let addr = &test.reg2 as *const GAP_TEST_reg2;
    assert_eq!(addr as usize - base as usize, 0x10);
  }

  #[test]
  fn computes_second_gap() {
    let test: GAP_TEST = zeroed_safe();
    let base = &test as *const GAP_TEST;
    let addr = &test.reg4 as *const GAP_TEST_reg4;
    assert_eq!(addr as usize - base as usize, 0x20);
  }

  /*
     describe!(
     before_each {
     let test: GAP_TEST = zeroed_safe();
     let base = &test as *const GAP_TEST;
     }
     it "has zero base offset" {
     let addr = &test.reg1 as *const GAP_TEST_reg1;
     assert_eq!(addr as usize - base as usize, 0x0);
     }
     it "computes the correct first gap" {
     let addr = &test.reg2 as *const GAP_TEST_reg2;
     assert_eq!(addr as usize - base as usize, 0x10);
     }
     it "computes the correct second gap" {
     let addr = &test.reg4 as *const GAP_TEST_reg4;
     assert_eq!(addr as usize - base as usize, 0x20);
     }
     );
     */

  ioregs!(MULTI_TEST @ 0 = {
    0x100 => reg32 reg1[8] {
      0..31 => field[32],
    }
  });

  #[test]
  fn multi_ok() {
    let test: MULTI_TEST = zeroed_safe();
    test.reg1[0].set_field(0, true);
    assert_eq!(test.reg1[0].field(0), true);
  }
}
<|endoftext|>