<commit_before>#![crate_type="dylib"]
#![feature(unique, shared)]
#![feature(proc_macro, try_from)]

mod classfactory; pub use classfactory::*;
mod combox; pub use combox::*;
mod comrc; pub use comrc::*;
mod comitf; pub use comitf::*;
mod bstr; pub use bstr::*;
mod guid; pub use guid::GUID;
mod error; pub use error::{return_hresult, get_last_error, ComError, ErrorInfo};

// The crate doesn't really need the macros. However Rust will complain that
// the import does nothing if we don't define #[macro_use]. Once we define
// #[macro_use] to get rid of that warning, Rust will complain that the
// #[macro_use] does nothing. Fortunately THAT warning comes with a named
// warning option so we can allow that explicitly.
//
// Unfortunately clippy disagrees on the macro_use being unused and claims that
// the unused_imports attribute is useless. So now we also need to tell clippy
// to ignore useless attributes in this scenario! \:D/
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
#[allow(unused_imports)]
extern crate intercom_attributes;
pub use intercom_attributes::*;

// intercom_attributes use "intercom::" to qualify things in this crate.
// Declare such module here and import everything we have in it to make those
// references valid.
mod intercom {
    pub use ::*;
}

/// Raw COM pointer type.
pub type RawComPtr = *mut std::os::raw::c_void;

/// 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;

/// COM error result value.
pub type HRESULT = i32;

/// `HRESULT` indicating the operation completed successfully.
pub const S_OK : HRESULT = 0;

/// `HRESULT` indicating the operation completed successfully and returned FALSE.
pub const S_FALSE : HRESULT = 1;

/// `HRESULT` for unimplemented functionality.
#[allow(overflowing_literals)]
pub const E_NOTIMPL : HRESULT = 0x8000_4001 as HRESULT;

/// `HRESULT` indicating the type does not support the requested interface.
#[allow(overflowing_literals)]
pub const E_NOINTERFACE : HRESULT = 0x8000_4002 as HRESULT;

/// `HRESULT` indicating a pointer parameter was invalid.
#[allow(overflowing_literals)]
pub const E_POINTER : HRESULT = 0x8000_4003 as HRESULT;

/// `HRESULT` for aborted operation.
#[allow(overflowing_literals)]
pub const E_ABORT : HRESULT = 0x8000_4004 as HRESULT;

/// `HRESULT` for unspecified failure.
#[allow(overflowing_literals)]
pub const E_FAIL : HRESULT = 0x8000_4005 as HRESULT;

/// `HRESULT` for invalid argument.
#[allow(overflowing_literals)]
pub const E_INVALIDARG : HRESULT = 0x8007_0057 as HRESULT;

#[allow(overflowing_literals)]
pub const E_ACCESSDENIED : HRESULT = 0x8007_0005 as HRESULT;

#[allow(overflowing_literals)]
pub const STG_E_FILENOTFOUND : HRESULT = 0x8003_0002 as HRESULT;

#[allow(overflowing_literals)]
pub const RPC_E_DISCONNECTED : HRESULT = 0x8001_0108 as HRESULT;

#[allow(overflowing_literals)]
pub const RPC_E_CALL_REJECTED : HRESULT = 0x8001_0001 as HRESULT;

#[allow(overflowing_literals)]
pub const RPC_E_CALL_CANCELED : HRESULT = 0x8001_0002 as HRESULT;

#[allow(overflowing_literals)]
pub const RPC_E_TIMEOUT : HRESULT = 0x8001_011F as HRESULT;

/// `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 ]
};

mod interfaces {

    #[::com_interface( "00000000-0000-0000-C000-000000000046", NO_BASE )]
    pub trait IUnknown {
        fn query_interface( &self, riid : ::REFIID ) -> ::ComResult< ::RawComPtr >;
        fn add_ref( &self ) -> u32;
        fn release( &self ) -> u32;
    }

    #[::com_interface( "DF0B3D60-548F-101B-8E65-08002B2BD119" )]
    pub trait ISupportErrorInfo {
        fn interface_supports_error_info( &self, riid : ::REFIID ) -> ::HRESULT;
    }
}

pub use interfaces::__IUnknownVtbl as IUnknownVtbl;
pub use interfaces::IID_IUnknown;
pub use interfaces::IUnknown;

pub use interfaces::__ISupportErrorInfoVtbl as ISupportErrorInfoVtbl;
pub use interfaces::IID_ISupportErrorInfo;
pub use interfaces::ISupportErrorInfo;

// Do we need this? Would rather not export this through an extern crate
// for another dll.
//
// com_library should have dllmain!() macro or similar that implements this
// together with the COM registration.
#[no_mangle]
#[allow(non_camel_case_types)]
pub extern "stdcall" fn DllMain(
    _dll_instance : *mut std::os::raw::c_void,
    _reason : u32,
    _reserved : *mut std::os::raw::c_void ) -> bool
{
    true
}

pub type ComResult<A> = Result<A, HRESULT>;

<commit_msg>Make HRESULT into struct<commit_after>#![crate_type="dylib"]
#![feature(unique, shared)]
#![feature(proc_macro, try_from)]

mod classfactory; pub use classfactory::*;
mod combox; pub use combox::*;
mod comrc; pub use comrc::*;
mod comitf; pub use comitf::*;
mod bstr; pub use bstr::*;
mod guid; pub use guid::GUID;
mod error; pub use error::{return_hresult, get_last_error, ComError, ErrorInfo};

// The crate doesn't really need the macros. However Rust will complain that
// the import does nothing if we don't define #[macro_use]. Once we define
// #[macro_use] to get rid of that warning, Rust will complain that the
// #[macro_use] does nothing. Fortunately THAT warning comes with a named
// warning option so we can allow that explicitly.
//
// Unfortunately clippy disagrees on the macro_use being unused and claims that
// the unused_imports attribute is useless. So now we also need to tell clippy
// to ignore useless attributes in this scenario! \:D/
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
#[allow(unused_imports)]
extern crate intercom_attributes;
pub use intercom_attributes::*;

// intercom_attributes use "intercom::" to qualify things in this crate.
// Declare such module here and import everything we have in it to make those
// references valid.
mod intercom {
    pub use ::*;
}

/// Raw COM pointer type.
pub type RawComPtr = *mut std::os::raw::c_void;

/// 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;

/// COM error result value.
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
#[repr(C)]
pub struct HRESULT { pub hr : i32 }

impl HRESULT {
    pub fn new( hr : u32 ) -> HRESULT {
        #[allow(overflowing_literals)]
        HRESULT { hr : hr as i32 }
    }
}

macro_rules! make_hr {
    ( $hr_name: ident, $hr_value: expr ) => {
        #[allow(overflowing_literals)]
        pub const $hr_name : HRESULT = HRESULT { hr: $hr_value as i32 };
    }
}

/// `HRESULT` indicating the operation completed successfully.
make_hr!( S_OK, 0 );

/// `HRESULT` indicating the operation completed successfully and returned FALSE.
make_hr!( S_FALSE, 1 );

/// `HRESULT` for unimplemented functionality.
make_hr!( E_NOTIMPL, 0x8000_4001 );

/// `HRESULT` indicating the type does not support the requested interface.
make_hr!( E_NOINTERFACE, 0x8000_4002 );

/// `HRESULT` indicating a pointer parameter was invalid.
make_hr!( E_POINTER, 0x8000_4003 );

/// `HRESULT` for aborted operation.
make_hr!( E_ABORT, 0x8000_4004 );

/// `HRESULT` for unspecified failure.
make_hr!( E_FAIL, 0x8000_4005 );

/// `HRESULT` for invalid argument.
make_hr!( E_INVALIDARG, 0x8007_0057 );

make_hr!( E_ACCESSDENIED, 0x8007_0005 );

make_hr!( STG_E_FILENOTFOUND, 0x8003_0002 );

make_hr!( RPC_E_DISCONNECTED, 0x8001_0108 );

make_hr!( RPC_E_CALL_REJECTED, 0x8001_0001 );

make_hr!( RPC_E_CALL_CANCELED, 0x8001_0002 );

make_hr!( RPC_E_TIMEOUT, 0x8001_011F );

/// `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 ]
};

mod interfaces {

    #[::com_interface( "00000000-0000-0000-C000-000000000046", NO_BASE )]
    pub trait IUnknown {
        fn query_interface( &self, riid : ::REFIID ) -> ::ComResult< ::RawComPtr >;
        fn add_ref( &self ) -> u32;
        fn release( &self ) -> u32;
    }

    #[::com_interface( "DF0B3D60-548F-101B-8E65-08002B2BD119" )]
    pub trait ISupportErrorInfo {
        fn interface_supports_error_info( &self, riid : ::REFIID ) -> ::HRESULT;
    }
}

pub use interfaces::__IUnknownVtbl as IUnknownVtbl;
pub use interfaces::IID_IUnknown;
pub use interfaces::IUnknown;

pub use interfaces::__ISupportErrorInfoVtbl as ISupportErrorInfoVtbl;
pub use interfaces::IID_ISupportErrorInfo;
pub use interfaces::ISupportErrorInfo;

// Do we need this? Would rather not export this through an extern crate
// for another dll.
//
// com_library should have dllmain!() macro or similar that implements this
// together with the COM registration.
#[no_mangle]
#[allow(non_camel_case_types)]
pub extern "stdcall" fn DllMain(
    _dll_instance : *mut std::os::raw::c_void,
    _reason : u32,
    _reserved : *mut std::os::raw::c_void ) -> bool
{
    true
}

pub type ComResult<A> = Result<A, HRESULT>;

<|endoftext|>


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

pub use parse::ParseError;

mod enums;
mod parse;

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

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

    let mut output = String::new();

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

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

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

        "#, name = name));

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

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

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

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

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

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

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

    Ok(output)
}

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

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

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

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

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

            // TODO: sort types by location

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pub use parse::ParseError;

mod enums;
mod parse;

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

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

    let mut output = String::new();

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

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

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

        "#, name = name));

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

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

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data).unwrap()    // FIXME: try!()
            }}
        }}
    }}

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

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

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

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

    Ok(output)
}

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

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

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

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

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

            // TODO: sort types by location

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


<commit_before>#[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
use petname::petname;
use petname::Petnames;
use rand::rngs::mock::StepRng;

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_adjectives() {
    let petnames = Petnames::default();
    assert_ne!(petnames.adjectives.len(), 0);
}

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_adverbs() {
    let petnames = Petnames::default();
    assert_ne!(petnames.adverbs.len(), 0);
}

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_names() {
    let petnames = Petnames::default();
    assert_ne!(petnames.names.len(), 0);
}

#[test]
fn retain_applies_given_predicate() {
    let petnames_expected = Petnames::init("bob", "bob", "bob jane");
    let mut petnames = Petnames::init("alice bob carol", "alice bob", "bob carol jane");
    petnames.retain(|word| word.len() < 5);
    assert_eq!(petnames_expected, petnames);
}

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_non_zero_cardinality() {
    let petnames = Petnames::default();
    // This test will need to be adjusted when word lists change.
    assert_eq!(0, petnames.cardinality(0));
    assert_eq!(456, petnames.cardinality(1));
    assert_eq!(204744, petnames.cardinality(2));
    assert_eq!(53438184, petnames.cardinality(3));
    assert_eq!(13947366024, petnames.cardinality(4));
}

#[test]
fn generate_uses_adverb_adjective_name() {
    let petnames = Petnames {
        adjectives: vec!["adjective"],
        adverbs: vec!["adverb"],
        names: vec!["name"],
    };
    assert_eq!(
        petnames.generate(&mut StepRng::new(0, 1), 3, "-"),
        "adverb-adjective-name"
    );
}

#[test]
#[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
fn petname_renders_desired_number_of_words() {
    assert_eq!(petname(7, "-").split('-').count(), 7);
}

#[test]
#[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
fn petname_renders_with_desired_separator() {
    assert_eq!(petname(7, "@").split('@').count(), 7);
}

#[test]
fn petnames_iter_has_cardinality() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("a b", "c d e", "f g h i");
    let names = petnames.iter(&mut rng, 3, ".");
    assert_eq!(24u128, names.cardinality());
}

#[test]
fn petnames_iter_yields_names() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("foo", "bar", "baz");
    let names = petnames.iter(&mut rng, 3, ".");
    // Definintely an Iterator...
    let mut iter: Box<dyn Iterator<Item = _>> = Box::new(names);
    assert_eq!(Some("bar.foo.baz".to_string()), iter.next());
}

#[test]
fn petnames_iter_unique_yields_unique_names() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("a1 a2", "b1 b2 b3", "c1 c2");
    let names = petnames.iter_unique(&mut rng, 3, ".");
    // Definintely an Iterator...
    let iter: Box<dyn Iterator<Item = _>> = Box::new(names);
    let names: Vec<String> = iter.collect();
    assert_eq!(
        vec![
            "b2.a2.c2", "b3.a2.c2", "b1.a2.c2", "b2.a1.c2", "b3.a1.c2", "b1.a1.c2", "b2.a2.c1",
            "b3.a2.c1", "b1.a2.c1", "b2.a1.c1", "b3.a1.c1", "b1.a1.c1"
        ],
        names
    )
}
<commit_msg>Test when one word list is empty<commit_after>#[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
use petname::petname;
use petname::Petnames;
use rand::rngs::mock::StepRng;

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_adjectives() {
    let petnames = Petnames::default();
    assert_ne!(petnames.adjectives.len(), 0);
}

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_adverbs() {
    let petnames = Petnames::default();
    assert_ne!(petnames.adverbs.len(), 0);
}

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_names() {
    let petnames = Petnames::default();
    assert_ne!(petnames.names.len(), 0);
}

#[test]
fn retain_applies_given_predicate() {
    let petnames_expected = Petnames::init("bob", "bob", "bob jane");
    let mut petnames = Petnames::init("alice bob carol", "alice bob", "bob carol jane");
    petnames.retain(|word| word.len() < 5);
    assert_eq!(petnames_expected, petnames);
}

#[test]
#[cfg(feature = "default_dictionary")]
fn default_petnames_has_non_zero_cardinality() {
    let petnames = Petnames::default();
    // This test will need to be adjusted when word lists change.
    assert_eq!(0, petnames.cardinality(0));
    assert_eq!(456, petnames.cardinality(1));
    assert_eq!(204744, petnames.cardinality(2));
    assert_eq!(53438184, petnames.cardinality(3));
    assert_eq!(13947366024, petnames.cardinality(4));
}

#[test]
fn generate_uses_adverb_adjective_name() {
    let petnames = Petnames {
        adjectives: vec!["adjective"],
        adverbs: vec!["adverb"],
        names: vec!["name"],
    };
    assert_eq!(
        petnames.generate(&mut StepRng::new(0, 1), 3, "-"),
        "adverb-adjective-name"
    );
}

#[test]
#[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
fn petname_renders_desired_number_of_words() {
    assert_eq!(petname(7, "-").split('-').count(), 7);
}

#[test]
#[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
fn petname_renders_with_desired_separator() {
    assert_eq!(petname(7, "@").split('@').count(), 7);
}

#[test]
fn petnames_iter_has_cardinality() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("a b", "c d e", "f g h i");
    let names = petnames.iter(&mut rng, 3, ".");
    assert_eq!(24u128, names.cardinality());
}

#[test]
fn petnames_iter_yields_names() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("foo", "bar", "baz");
    let names = petnames.iter(&mut rng, 3, ".");
    // Definintely an Iterator...
    let mut iter: Box<dyn Iterator<Item = _>> = Box::new(names);
    assert_eq!(Some("bar.foo.baz".to_string()), iter.next());
}

#[test]
fn petnames_iter_unique_yields_unique_names() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("a1 a2", "b1 b2 b3", "c1 c2");
    let names = petnames.iter_unique(&mut rng, 3, ".");
    // Definintely an Iterator...
    let iter: Box<dyn Iterator<Item = _>> = Box::new(names);
    let names: Vec<String> = iter.collect();
    assert_eq!(
        vec![
            "b2.a2.c2", "b3.a2.c2", "b1.a2.c2", "b2.a1.c2", "b3.a1.c2", "b1.a1.c2", "b2.a2.c1",
            "b3.a2.c1", "b1.a2.c1", "b2.a1.c1", "b3.a1.c1", "b1.a1.c1"
        ],
        names
    )
}

#[test]
fn petnames_iter_unique_yields_nothing_when_any_word_list_is_empty() {
    let mut rng = StepRng::new(0, 1);
    let petnames = Petnames::init("a1 a2", "", "c1 c2");
    let names = petnames.iter_unique(&mut rng, 3, ".");
    // Definintely an Iterator...
    let iter: Box<dyn Iterator<Item = _>> = Box::new(names);
    let names: Vec<String> = iter.collect();
    assert!(names.is_empty())
}
<|endoftext|>


<commit_before>#![crate_name = "uu_factor"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
*     20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
*     20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate rand;

#[macro_use]
extern crate uucore;

use std::collections::HashMap;
use std::fmt;
use std::io::{stdin, BufRead};
use std::ops;

mod numeric;
mod rho;
mod table;

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

struct Factors {
    f: HashMap<u64, u8>,
}

impl Factors {
    fn new() -> Factors {
        Factors { f: HashMap::new() }
    }

    fn add(&mut self, prime: u64, exp: u8) {
        assert!(exp > 0);
        self.f.insert(prime, exp + self.f.get(&prime).unwrap_or(&0));
    }

    fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }
}

impl ops::MulAssign<Factors> for Factors {
    fn mul_assign(&mut self, other: Factors) {
        for (prime, exp) in &other.f {
            self.add(*prime, *exp);
        }
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TODO: Use a representation with efficient in-order iteration
        let mut primes: Vec<&u64> = self.f.keys().collect();
        primes.sort();

        for p in primes {
            for _ in 0..self.f[&p] {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::new();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n = n >> z;
    }

    if n == 1 {
        return factors;
    }

    if numeric::is_prime(n) {
        factors.push(n);
        return factors;
    }

    let (f, n) = table::factor(n);
    factors *= f;
    factors *= rho::factor(n);
    factors
}

fn print_factors(num: u64) {
    print!("{}:{}", num, factor(num));
    println!();
}

fn print_factors_str(num_str: &str) {
    if let Err(e) = num_str.parse::<u64>().and_then(|x| {
        print_factors(x);
        Ok(())
    }) {
        show_warning!("{}: {}", num_str, e);
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    if matches.free.is_empty() {
        let stdin = stdin();
        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                print_factors_str(number);
            }
        }
    } else {
        for num_str in &matches.free {
            print_factors_str(num_str);
        }
    }
    0
}
<commit_msg>factor::factor: Short-circuit the fallback to Pollard's rho<commit_after>#![crate_name = "uu_factor"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
*     20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
*     20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate rand;

#[macro_use]
extern crate uucore;

use std::collections::HashMap;
use std::fmt;
use std::io::{stdin, BufRead};
use std::ops;

mod numeric;
mod rho;
mod table;

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

struct Factors {
    f: HashMap<u64, u8>,
}

impl Factors {
    fn new() -> Factors {
        Factors { f: HashMap::new() }
    }

    fn add(&mut self, prime: u64, exp: u8) {
        assert!(exp > 0);
        self.f.insert(prime, exp + self.f.get(&prime).unwrap_or(&0));
    }

    fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }
}

impl ops::MulAssign<Factors> for Factors {
    fn mul_assign(&mut self, other: Factors) {
        for (prime, exp) in &other.f {
            self.add(*prime, *exp);
        }
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TODO: Use a representation with efficient in-order iteration
        let mut primes: Vec<&u64> = self.f.keys().collect();
        primes.sort();

        for p in primes {
            for _ in 0..self.f[&p] {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::new();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n = n >> z;
    }

    if n == 1 {
        return factors;
    }

    if numeric::is_prime(n) {
        factors.push(n);
        return factors;
    }

    let (f, n) = table::factor(n);
    factors *= f;

    if n >= table::NEXT_PRIME {
        factors *= rho::factor(n);
    }

    factors
}

fn print_factors(num: u64) {
    print!("{}:{}", num, factor(num));
    println!();
}

fn print_factors_str(num_str: &str) {
    if let Err(e) = num_str.parse::<u64>().and_then(|x| {
        print_factors(x);
        Ok(())
    }) {
        show_warning!("{}: {}", num_str, e);
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    if matches.free.is_empty() {
        let stdin = stdin();
        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                print_factors_str(number);
            }
        }
    } else {
        for num_str in &matches.free {
            print_factors_str(num_str);
        }
    }
    0
}
<|endoftext|>


<commit_before>//! # FFI bindings to N-API symbols
//!
//! These types are manually copied from bindings generated from `bindgen`. To
//! update, use the following approach:
//!
//! * Run `cargo build` with `--cfg neon=dev` at least once to install `nodejs-sys`
//! * Open the generated bindings at `target/debug/build/nodejs-sys-*/out/bindings.rs`
//! * Copy the types needed into `types.rs` and `functions.rs`
//! * Modify to match Rust naming conventions:
//!   - Remove `napi_` prefixes
//!   - Use `PascalCase` for types
//!   - Rename types that match a reserved word

/// Constructs the name of a N-API symbol as a string from a function identifier
/// E.g., `get_undefined` becomes `"napi_get_undefined"`
macro_rules! napi_name {
    // Explicitly replace identifiers that have been renamed from the N-API
    // symbol because they would match a reserved word.
    (typeof_value) => {
        "napi_typeof"
    };
    // Default case: Stringify the identifier and prefix with `napi_`
    ($name:ident) => {
        concat!("napi_", stringify!($name))
    };
}

/// Generate dynamic bindings to N-API symbols from definitions in an
/// block `extern "C"`.
///
/// * A single global mutable struct holds references to the N-API functions
/// * The global `Napi` struct  is initialized with stubs that panic if called
/// * A `load` function is generated that loads the N-API symbols from the
///   host process and replaces the global struct with real implementations
/// * `load` should be called exactly once before using any N-API functions
/// * Wrapper functions are generated to delegate to fields in the `Napi` struct
///
/// Sample input:
///
/// ```
/// extern "C" {
///     fn get_undefined(env: Env, result: *mut Value) -> Status;
///     /* Additional functions may be included */
/// }
/// ```
///
/// Generated output:
///
/// ```
/// // Each field is a pointer to a N-API function
/// struct Napi {
///     get_undefined: unsafe extern "C" fn(env: Env, result: *mut Value) -> Status,
///     /* ... repeat for each N-API function */
/// }
///
/// // Defines a panic function that is called if symbols have not been loaded
/// #[inline(never)]
/// fn panic_load<T>() -> T {
///     panic!("Must load N-API bindings")
/// }
///
/// // Mutable global instance of the Napi struct
/// // Initialized with stubs of N-API methods that panic
/// static mut NAPI: Napi = {
///     // Stubs are defined in a block to prevent naming conflicts with wrappers
///     unsafe extern "C" fn get_undefined(_: Env, _: *mut Value) -> Status {
///         panic_load()
///     }
///     /* ... repeat for each N-API function */
///
///     Napi {
///         get_undefined,
///         /* ... repeat for each N-API function */
///     }
/// };
///
/// // Load N-API symbols from the host process
/// // # Safety: Must only be called once
/// pub(super) unsafe fn load(
///     host: &libloading::Library,
///     actual_napi_version: u32,
///     expected_napi_version: u32,
/// ) -> Result<(), libloading::Error> {
///     assert!(
///         actual_napi_version >= expected_napi_version,
///         "Minimum required N-API version {}, found {}.",
///         expected_napi_version,
///         actual_napi_version,
///     );
///
///     NAPI = Napi {
///         // Load each N-API symbol
///         get_undefined: *host.get("napi_get_undefined".as_bytes())?,
///         /* ... repeat for each N-API function */
///     };
///
///     Ok(())
/// }
///
/// // Each N-API function has wrapper for easy calling. These calls are optimized
/// // to a single pointer dereference.
/// #[inline]
/// pub(crate) unsafe fn get_undefined(env: Env, result: *mut Value) -> Status {
///     (NAPI.get_undefined)(env, result)
/// }
/// ```
macro_rules! generate {
    (extern "C" {
        $(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
    }) => {
        struct Napi {
            $(
                $name: unsafe extern "C" fn(
                    $($param: $ptype,)*
                )$( -> $rtype)*,
            )*
        }

        #[inline(never)]
        fn panic_load<T>() -> T {
            panic!("Must load N-API bindings")
        }

        static mut NAPI: Napi = {
            $(
                unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
                    panic_load()
                }
            )*

            Napi {
                $(
                    $name,
                )*
            }
        };

        pub(super) unsafe fn load(
            host: &libloading::Library,
            actual_napi_version: u32,
            expected_napi_version: u32,
        ) -> Result<(), libloading::Error> {
            assert!(
                actual_napi_version >= expected_napi_version,
                "Minimum required N-API version {}, found {}.",
                expected_napi_version,
                actual_napi_version,
            );

            NAPI = Napi {
                $(
                    $name: *host.get(napi_name!($name).as_bytes())?,
                )*
            };

            Ok(())
        }

        $(
            #[inline]
            pub(crate) unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
                (NAPI.$name)($($param,)*)
            }
        )*
    };
}

use std::sync::Once;

pub(crate) use self::{functions::*, types::*};

mod functions;
mod types;

static SETUP: Once = Once::new();

/// Loads N-API symbols from host process.
/// Must be called at least once before using any functions in bindings or
/// they will panic.
/// Safety: `env` must be a valid `napi_env` for the current thread
pub(crate) unsafe fn setup(env: Env) {
    SETUP.call_once(|| load(env).expect("Failed to load N-API symbols"));
}
<commit_msg>Ignore doc tests for some example macro output<commit_after>//! # FFI bindings to N-API symbols
//!
//! These types are manually copied from bindings generated from `bindgen`. To
//! update, use the following approach:
//!
//! * Run `cargo build` with `--cfg neon=dev` at least once to install `nodejs-sys`
//! * Open the generated bindings at `target/debug/build/nodejs-sys-*/out/bindings.rs`
//! * Copy the types needed into `types.rs` and `functions.rs`
//! * Modify to match Rust naming conventions:
//!   - Remove `napi_` prefixes
//!   - Use `PascalCase` for types
//!   - Rename types that match a reserved word

/// Constructs the name of a N-API symbol as a string from a function identifier
/// E.g., `get_undefined` becomes `"napi_get_undefined"`
macro_rules! napi_name {
    // Explicitly replace identifiers that have been renamed from the N-API
    // symbol because they would match a reserved word.
    (typeof_value) => {
        "napi_typeof"
    };
    // Default case: Stringify the identifier and prefix with `napi_`
    ($name:ident) => {
        concat!("napi_", stringify!($name))
    };
}

/// Generate dynamic bindings to N-API symbols from definitions in an
/// block `extern "C"`.
///
/// * A single global mutable struct holds references to the N-API functions
/// * The global `Napi` struct  is initialized with stubs that panic if called
/// * A `load` function is generated that loads the N-API symbols from the
///   host process and replaces the global struct with real implementations
/// * `load` should be called exactly once before using any N-API functions
/// * Wrapper functions are generated to delegate to fields in the `Napi` struct
///
/// Sample input:
///
/// ```ignore
/// extern "C" {
///     fn get_undefined(env: Env, result: *mut Value) -> Status;
///     /* Additional functions may be included */
/// }
/// ```
///
/// Generated output:
///
/// ```ignore
/// // Each field is a pointer to a N-API function
/// struct Napi {
///     get_undefined: unsafe extern "C" fn(env: Env, result: *mut Value) -> Status,
///     /* ... repeat for each N-API function */
/// }
///
/// // Defines a panic function that is called if symbols have not been loaded
/// #[inline(never)]
/// fn panic_load<T>() -> T {
///     panic!("Must load N-API bindings")
/// }
///
/// // Mutable global instance of the Napi struct
/// // Initialized with stubs of N-API methods that panic
/// static mut NAPI: Napi = {
///     // Stubs are defined in a block to prevent naming conflicts with wrappers
///     unsafe extern "C" fn get_undefined(_: Env, _: *mut Value) -> Status {
///         panic_load()
///     }
///     /* ... repeat for each N-API function */
///
///     Napi {
///         get_undefined,
///         /* ... repeat for each N-API function */
///     }
/// };
///
/// // Load N-API symbols from the host process
/// // # Safety: Must only be called once
/// pub(super) unsafe fn load(
///     host: &libloading::Library,
///     actual_napi_version: u32,
///     expected_napi_version: u32,
/// ) -> Result<(), libloading::Error> {
///     assert!(
///         actual_napi_version >= expected_napi_version,
///         "Minimum required N-API version {}, found {}.",
///         expected_napi_version,
///         actual_napi_version,
///     );
///
///     NAPI = Napi {
///         // Load each N-API symbol
///         get_undefined: *host.get("napi_get_undefined".as_bytes())?,
///         /* ... repeat for each N-API function */
///     };
///
///     Ok(())
/// }
///
/// // Each N-API function has wrapper for easy calling. These calls are optimized
/// // to a single pointer dereference.
/// #[inline]
/// pub(crate) unsafe fn get_undefined(env: Env, result: *mut Value) -> Status {
///     (NAPI.get_undefined)(env, result)
/// }
/// ```
macro_rules! generate {
    (extern "C" {
        $(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
    }) => {
        struct Napi {
            $(
                $name: unsafe extern "C" fn(
                    $($param: $ptype,)*
                )$( -> $rtype)*,
            )*
        }

        #[inline(never)]
        fn panic_load<T>() -> T {
            panic!("Must load N-API bindings")
        }

        static mut NAPI: Napi = {
            $(
                unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
                    panic_load()
                }
            )*

            Napi {
                $(
                    $name,
                )*
            }
        };

        pub(super) unsafe fn load(
            host: &libloading::Library,
            actual_napi_version: u32,
            expected_napi_version: u32,
        ) -> Result<(), libloading::Error> {
            assert!(
                actual_napi_version >= expected_napi_version,
                "Minimum required N-API version {}, found {}.",
                expected_napi_version,
                actual_napi_version,
            );

            NAPI = Napi {
                $(
                    $name: *host.get(napi_name!($name).as_bytes())?,
                )*
            };

            Ok(())
        }

        $(
            #[inline]
            pub(crate) unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
                (NAPI.$name)($($param,)*)
            }
        )*
    };
}

use std::sync::Once;

pub(crate) use self::{functions::*, types::*};

mod functions;
mod types;

static SETUP: Once = Once::new();

/// Loads N-API symbols from host process.
/// Must be called at least once before using any functions in bindings or
/// they will panic.
/// Safety: `env` must be a valid `napi_env` for the current thread
pub(crate) unsafe fn setup(env: Env) {
    SETUP.call_once(|| load(env).expect("Failed to load N-API symbols"));
}
<|endoftext|>


<commit_before>extern crate ktensor as k;
use k::{Arc, Vec2, Tensor, Context, Graph, State, Variable};
use std::path::{Path};
use std::fs::{File};
use std::io::{BufReader, Read};
use std::error::{Error};
use std::cmp;

fn read_u8(reader: &mut Read) -> u8 {
    use std::mem;

    let mut buf: [u8; 1] = [0];
    match reader.read_exact(&mut buf).map(|_| {
        let data: u8 = unsafe { mem::transmute(buf) };
        data
    }) {
        Err(reason) => panic!("failed to read u8: {}", Error::description(&reason)),
        Ok(byte)    => byte,
    }
}

fn read_u32(reader: &mut Read) -> u32 {
    use std::mem;

    let mut buf: [u8; 4] = [0, 0, 0, 0];
    match reader.read_exact(&mut buf).map(|_| {
        let data: u32 = unsafe { mem::transmute(buf) };
        data
    }) {
        Err(reason) => panic!("failed to read u32: {}", Error::description(&reason)),
        Ok(byte)    => byte,
    }
}

fn read_mnist(labels_path: &Path, labels_checknum: u32, data_path: &Path, data_checknum: u32, batch_size: Option<usize>, sample_size: Option<usize>) -> Vec<(Tensor<f32>, Tensor<f32>)> {
    let labels_file = match File::open(&labels_path) {
        Err(reason) => panic!("failed to open {}: {}", labels_path.display(), Error::description(&reason)),
        Ok(file)    => file,
    };
    let data_file = match File::open(&data_path) {
        Err(reason) => panic!("failed to open {}: {}", data_path.display(), Error::description(&reason)),
        Ok(file)    => file,
    };
    let ref mut labels_reader = BufReader::new(labels_file);
    let ref mut data_reader = BufReader::new(data_file);

    let labels_magic = u32::from_be(read_u32(labels_reader));
    let data_magic = u32::from_be(read_u32(data_reader));

    assert_eq!(labels_magic, labels_checknum);
    assert_eq!(data_magic, data_checknum);

    let labels_count = u32::from_be(read_u32(labels_reader)) as usize;
    let data_count = u32::from_be(read_u32(data_reader)) as usize;
    let sample_count = cmp::min(labels_count, data_count);
    let sample_count = cmp::min(sample_count, sample_size.unwrap_or(sample_count));

    let batch_count = cmp::min(sample_count, batch_size.unwrap_or(sample_count));

    let rows = u32::from_be(read_u32(data_reader)) as usize;
    let columns = u32::from_be(read_u32(data_reader)) as usize;

    let mut sample_vec: Vec<(Tensor<f32>, Tensor<f32>)> = Vec::with_capacity(sample_count/batch_count);
    for _ in 0..sample_count/batch_count {
        let mut sample_data = vec![0u8; batch_count*rows*columns];
        match data_reader.read_exact(sample_data.as_mut()) {
            Err(reason) => panic!("failed to read data byte array: {}", Error::description(&reason)),
            Ok(_)       => (),
        }
        let mut sample_labels_byte = vec![0u8; batch_count];
        match labels_reader.read_exact(sample_labels_byte.as_mut()) {
            Err(reason) => panic!("failed to read labels byte array: {}", Error::description(&reason)),
            Ok(_)       => (),
        }

        let sample_data = sample_data.iter().map(|&x| x as f32).collect();
        let mut sample_labels: Vec<f32> = Vec::with_capacity(batch_count * 10);
        for i in sample_labels_byte {
            match i {
                0 => sample_labels.extend([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                1 => sample_labels.extend([0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                2 => sample_labels.extend([0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                3 => sample_labels.extend([0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                4 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                5 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                6 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0].iter().cloned()),
                7 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0].iter().cloned()),
                8 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0].iter().cloned()),
                9 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0].iter().cloned()),
                _ => (),
            }
        }

        sample_vec.push((Tensor::from_vec(Vec2(batch_count, rows*columns), sample_data), Tensor::from_vec(Vec2(batch_count, 10), sample_labels)));
    }

    sample_vec
}

#[test]
#[ignore]
fn mnist(){
    ///////////////
    // Variables //
    ///////////////

    let input_x = Arc::new(Variable::new("input_x".to_string(), Vec2(0, 28 * 28)));
    let target_y = Arc::new(Variable::new("target_y".to_string(), Vec2(0, 10)));

    // Initialize
    let mut variable_context = Context::<f32>::with_capacity(2);
    Variable::init_f32(vec![input_x.clone(), target_y.clone()], &mut variable_context);

    ///////////
    // Graph //
    ///////////

    let layers: usize = 2;
    let mut states = Vec::<Arc<State>>::with_capacity(2 * layers);
    let mut graph_head: Arc<Graph<f32>> = input_x.clone();

    {
        let w = Arc::new(State::new(format!("weight_w_{}", 1), Vec2(28 * 28, 16)));
        let b = Arc::new(State::new(format!("weight_b_{}", 1), Vec2(1, 16)));

        let dot = Arc::new(k::op::dot::<f32>(format!("layer_{}_dot", 1), graph_head.clone(), w.clone()));
        let add = Arc::new(k::op::add::<f32>(format!("layer_{}_add", 1), dot, b.clone()));

        let relu = Arc::new(k::op::relu_f32(format!("layer_{}_relu", 1), add));

        graph_head = relu;

        states.push(w);
        states.push(b);
    }

    {
        let w = Arc::new(State::new(format!("weight_w_{}", 2), Vec2(16, 10)));
        let b = Arc::new(State::new(format!("weight_b_{}", 2), Vec2(1, 10)));

        let dot = Arc::new(k::op::dot::<f32>(format!("layer_{}_dot", 2), graph_head.clone(), w.clone()));
        let add = Arc::new(k::op::add::<f32>(format!("layer_{}_add", 2), dot, b.clone()));

        let relu = Arc::new(k::op::relu_f32(format!("layer_{}_relu", 2), add));

        graph_head = relu;

        states.push(w);
        states.push(b);
    }

    let softmax = Arc::new(k::op::softmax_f32(format!("layer_{}_softmax", 3), graph_head.clone()));
    let xentropy = Arc::new(k::cost::softmax_cross_entropy_f32(format!("layer_{}_xentropy", 3), softmax.clone(), target_y.clone()));

    // initialize states
    let mut state_context = Context::<f32>::with_capacity(2 * layers);
    State::init_f32(states, &mut state_context);

    //////////////
    // Training //
    //////////////
    {
        // Parameters
        let batch_size = Some(16);
        let sample_size = Some(4096);
        let learning_rate = -0.1;
        let iterations = 16384;
        let print_rate = 4096;

        let train_labels_path = Path::new("data/train-labels-idx1-ubyte");
        let train_data_path = Path::new("data/train-images-idx3-ubyte");
        let training_vec = read_mnist(&train_labels_path, 2049, &train_data_path, 2051, batch_size, sample_size);

        let mut history = Context::<f32>::with_capacity(5 * layers + 4);

        let training_vec_length = training_vec.len();
        for i in 0..iterations {
            let (ref a, ref b) = training_vec[i % training_vec_length];
            variable_context.set(input_x.get_id(), a.clone());
            variable_context.set(target_y.get_id(), b.clone());

            k::train(xentropy.clone(), &mut state_context, &variable_context, &mut history, learning_rate);

            // test print
            if i % print_rate == 0 {
                println!("\niteration: {} | cross entropy cost: {}", i,
                k::execute(xentropy.clone(), &state_context, &variable_context).get(Vec2(0, 0)));
            }
        }
    }

    ////////////////
    // Final test //
    ////////////////
    {
        println!("\nFinal Test:\n");
        // Parameters
        let batch_size = None;
        let sample_size = None;
        let print_rate = 4096;

        let test_labels_path = Path::new("data/t10k-labels-idx1-ubyte");
        let test_data_path = Path::new("data/t10k-images-idx3-ubyte");
        let test_vec = read_mnist(&test_labels_path, 2049, &test_data_path, 2051, batch_size, sample_size);

        let mut history = Context::<f32>::with_capacity(5 * layers + 4);

        let score = 0.0;
        let (ref a, ref b) = test_vec[0];
        variable_context.set(input_x.get_id(), a.clone());
        variable_context.set(target_y.get_id(), b.clone());
    }
}
<commit_msg>mnist final test<commit_after>extern crate ktensor as k;
use k::{Arc, Vec2, Tensor, Context, Graph, State, Variable};
use std::path::{Path};
use std::fs::{File};
use std::io::{BufReader, Read};
use std::error::{Error};
use std::cmp;

fn read_u8(reader: &mut Read) -> u8 {
    use std::mem;

    let mut buf: [u8; 1] = [0];
    match reader.read_exact(&mut buf).map(|_| {
        let data: u8 = unsafe { mem::transmute(buf) };
        data
    }) {
        Err(reason) => panic!("failed to read u8: {}", Error::description(&reason)),
        Ok(byte)    => byte,
    }
}

fn read_u32(reader: &mut Read) -> u32 {
    use std::mem;

    let mut buf: [u8; 4] = [0, 0, 0, 0];
    match reader.read_exact(&mut buf).map(|_| {
        let data: u32 = unsafe { mem::transmute(buf) };
        data
    }) {
        Err(reason) => panic!("failed to read u32: {}", Error::description(&reason)),
        Ok(byte)    => byte,
    }
}

fn read_mnist(labels_path: &Path, labels_checknum: u32, data_path: &Path, data_checknum: u32, batch_size: Option<usize>, sample_size: Option<usize>) -> Vec<(Tensor<f32>, Tensor<f32>)> {
    let labels_file = match File::open(&labels_path) {
        Err(reason) => panic!("failed to open {}: {}", labels_path.display(), Error::description(&reason)),
        Ok(file)    => file,
    };
    let data_file = match File::open(&data_path) {
        Err(reason) => panic!("failed to open {}: {}", data_path.display(), Error::description(&reason)),
        Ok(file)    => file,
    };
    let ref mut labels_reader = BufReader::new(labels_file);
    let ref mut data_reader = BufReader::new(data_file);

    let labels_magic = u32::from_be(read_u32(labels_reader));
    let data_magic = u32::from_be(read_u32(data_reader));

    assert_eq!(labels_magic, labels_checknum);
    assert_eq!(data_magic, data_checknum);

    let labels_count = u32::from_be(read_u32(labels_reader)) as usize;
    let data_count = u32::from_be(read_u32(data_reader)) as usize;
    let sample_count = cmp::min(labels_count, data_count);
    let sample_count = cmp::min(sample_count, sample_size.unwrap_or(sample_count));

    let batch_count = cmp::min(sample_count, batch_size.unwrap_or(sample_count));

    let rows = u32::from_be(read_u32(data_reader)) as usize;
    let columns = u32::from_be(read_u32(data_reader)) as usize;

    let mut sample_vec: Vec<(Tensor<f32>, Tensor<f32>)> = Vec::with_capacity(sample_count/batch_count);
    for _ in 0..sample_count/batch_count {
        let mut sample_data = vec![0u8; batch_count*rows*columns];
        match data_reader.read_exact(sample_data.as_mut()) {
            Err(reason) => panic!("failed to read data byte array: {}", Error::description(&reason)),
            Ok(_)       => (),
        }
        let mut sample_labels_byte = vec![0u8; batch_count];
        match labels_reader.read_exact(sample_labels_byte.as_mut()) {
            Err(reason) => panic!("failed to read labels byte array: {}", Error::description(&reason)),
            Ok(_)       => (),
        }

        let sample_data = sample_data.iter().map(|&x| x as f32).collect();
        let mut sample_labels: Vec<f32> = Vec::with_capacity(batch_count * 10);
        for i in sample_labels_byte {
            match i {
                0 => sample_labels.extend([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                1 => sample_labels.extend([0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                2 => sample_labels.extend([0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                3 => sample_labels.extend([0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                4 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                5 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0].iter().cloned()),
                6 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0].iter().cloned()),
                7 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0].iter().cloned()),
                8 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0].iter().cloned()),
                9 => sample_labels.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0].iter().cloned()),
                _ => (),
            }
        }

        sample_vec.push((Tensor::from_vec(Vec2(batch_count, rows*columns), sample_data), Tensor::from_vec(Vec2(batch_count, 10), sample_labels)));
    }

    sample_vec
}

#[test]
#[ignore]
fn mnist(){
    ///////////////
    // Variables //
    ///////////////

    let input_x = Arc::new(Variable::new("input_x".to_string(), Vec2(0, 28 * 28)));
    let target_y = Arc::new(Variable::new("target_y".to_string(), Vec2(0, 10)));

    // Initialize
    let mut variable_context = Context::<f32>::with_capacity(2);
    Variable::init_f32(vec![input_x.clone(), target_y.clone()], &mut variable_context);

    ///////////
    // Graph //
    ///////////

    let layers: usize = 2;
    let mut states = Vec::<Arc<State>>::with_capacity(2 * layers);
    let mut graph_head: Arc<Graph<f32>> = input_x.clone();

    {
        let w = Arc::new(State::new(format!("weight_w_{}", 1), Vec2(28 * 28, 16)));
        let b = Arc::new(State::new(format!("weight_b_{}", 1), Vec2(1, 16)));

        let dot = Arc::new(k::op::dot::<f32>(format!("layer_{}_dot", 1), graph_head.clone(), w.clone()));
        let add = Arc::new(k::op::add::<f32>(format!("layer_{}_add", 1), dot, b.clone()));

        let relu = Arc::new(k::op::relu_f32(format!("layer_{}_relu", 1), add));

        graph_head = relu;

        states.push(w);
        states.push(b);
    }

    {
        let w = Arc::new(State::new(format!("weight_w_{}", 2), Vec2(16, 10)));
        let b = Arc::new(State::new(format!("weight_b_{}", 2), Vec2(1, 10)));

        let dot = Arc::new(k::op::dot::<f32>(format!("layer_{}_dot", 2), graph_head.clone(), w.clone()));
        let add = Arc::new(k::op::add::<f32>(format!("layer_{}_add", 2), dot, b.clone()));

        let relu = Arc::new(k::op::relu_f32(format!("layer_{}_relu", 2), add));

        graph_head = relu;

        states.push(w);
        states.push(b);
    }

    let softmax = Arc::new(k::op::softmax_f32(format!("layer_{}_softmax", 3), graph_head.clone()));
    let xentropy = Arc::new(k::cost::softmax_cross_entropy_f32(format!("layer_{}_xentropy", 3), softmax.clone(), target_y.clone()));

    // initialize states
    let mut state_context = Context::<f32>::with_capacity(2 * layers);
    State::init_f32(states, &mut state_context);

    //////////////
    // Training //
    //////////////
    {
        // Parameters
        let batch_size = Some(16);
        let sample_size = Some(4096);
        let learning_rate = -0.1;
        let iterations = 16384;
        let print_rate = 4096;

        let train_labels_path = Path::new("data/train-labels-idx1-ubyte");
        let train_data_path = Path::new("data/train-images-idx3-ubyte");
        let training_vec = read_mnist(&train_labels_path, 2049, &train_data_path, 2051, batch_size, sample_size);

        let mut history = Context::<f32>::with_capacity(5 * layers + 4);

        let training_vec_length = training_vec.len();
        for i in 0..iterations {
            let (ref a, ref b) = training_vec[i % training_vec_length];
            variable_context.set(input_x.get_id(), a.clone());
            variable_context.set(target_y.get_id(), b.clone());

            k::train(xentropy.clone(), &mut state_context, &variable_context, &mut history, learning_rate);

            // test print
            if i % print_rate == 0 {
                println!("\niteration: {} | cross entropy cost: {}", i,
                k::execute(xentropy.clone(), &state_context, &variable_context).get(Vec2(0, 0)));
            }
        }
    }

    ////////////////
    // Final test //
    ////////////////
    {
        println!("\nFinal Test:\n");
        // Parameters
        let batch_size = None;
        let sample_size = None;
        let print_rate = 4096;

        let test_labels_path = Path::new("data/t10k-labels-idx1-ubyte");
        let test_data_path = Path::new("data/t10k-images-idx3-ubyte");
        let test_vec = read_mnist(&test_labels_path, 2049, &test_data_path, 2051, batch_size, sample_size);

        let (ref a, ref b) = test_vec[0];
        variable_context.set(input_x.get_id(), a.clone());
        variable_context.set(target_y.get_id(), b.clone());

        let result_tensor = k::op::softmax_round_f32(k::execute(softmax.clone(), &state_context, &variable_context)) + (k::op::softmax_round_f32(b.clone()) * &-1.0);
        let total = result_tensor.buffer().len() as f64;
        let score = 0.0;
        for i in result_tensor.buffer().iter() {
            if i == 0.0 {
                score += 1.0;
            }
        }

        println!("{}", score/total);
    }
}
<|endoftext|>


<commit_before>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

#[link(name = "str2", author = "kcantu", vers = "0.0")];
use std;

// a better slice, unicode safe
// since strings are null terminated, cannot copy in place
//
// start is the character position to begin copying
// end is the character position which should not be copied
//
// Does not make internal conversion to char (which is UTF-32/UCS-4),
// but is UTF-8 aware.
//

// helper: note, slice_chars could be faster (by not starting byte_position from zero the second time)
// if this was a named block internal to slice_chars
fn byte_position (&&ss: str, char_position: uint) -> uint
{
   let cursor_char = 0u;
   let cursor_byte = 0u;

   while cursor_char < char_position {
      let sz = str::utf8_char_width(ss[cursor_byte]);
      assert sz > 0u;
      cursor_byte += sz;
      cursor_char += 1u;
   }
   assert cursor_char <= str::char_len(ss);
   assert cursor_byte <= str::byte_len(ss);
   ret cursor_byte;
}

fn slice_chars(ss: str, begin: uint, end: uint) -> str unsafe
{
   assert begin <= end;
   assert end <= str::char_len(ss);

   // find the begin and end
   let byte_begin = byte_position(ss, begin);
//   std::io::println(#fmt("begin: %u", byte_begin));
   let byte_end   = byte_position(ss, end);
//   std::io::println(#fmt("end: %u", byte_end));

   // copy the bytes
   let new_vector = [];
   let ii = byte_begin;

   while ii < byte_end {
//      std::io::println(#fmt("pushing another u8: {%02x}", ss[ii] as uint));
      vec::push(new_vector, ss[ii]);
      ii += 1u;
   }
   vec::push(new_vector, 0u8);

   // return as a string
   let new_string: str = unsafe::reinterpret_cast(new_vector);
   unsafe::leak(new_vector);
   ret new_string;
}

#[test]
fn test_slice() {
    assert (str::eq("ab", slice_chars("abc", 0u, 2u)));
    assert (str::eq("bc", slice_chars("abc", 1u, 3u)));
    assert (str::eq("", slice_chars("abc", 1u, 1u)));
    fn a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaaaaaaa"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaa"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_a(),
                    slice_chars(a_million_letter_a(), 0u, 500000u)));
}

#[test]
fn test_slice_with_unicode_a() {
    let data = "ประเทศไทย中华Việt Nam";

    let wtf = slice_chars(data, 0u, 1u);
    std::io::println(#fmt("WHAT ABOUT: {%02x, %02x, %02x}", wtf[0] as uint, wtf[1] as uint, wtf[2] as uint));

    assert (str::eq("ปร", slice_chars(data, 0u, 2u)));
    assert (str::eq("ระ", slice_chars(data, 1u, 3u)));
    assert (str::eq("", slice_chars(data, 1u, 1u)));
}

#[test]
fn test_slice_with_unicode_b() {
    fn a_million_letter_X() -> str {
        let i = 0;
        let rs = "";
        while i < 100 { rs += "华华"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_X() -> str {
        let i = 0;
        let rs = "";
        while i < 100 { rs += "华"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_X(),
                    slice_chars(a_million_letter_X(), 0u, 100u)));
}

#[test]
fn equals_unicode() {
   let data = "ประเทศไทย中华Việt Nam";
   let data2 = "ประเทศไทย中华Việt Nam";
   assert str::eq(data,data2);

   assert str::eq("华", "华");
   assert str::eq("华华", "华华");
}

// a more general split, unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: fn&(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a ()
{
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example ()
{
   let s = "中华Việt Nam";
   let i = 0u;
   while i < str::byte_len(s)
   {
      let {ch:c, next:j} = str::char_range_at(s, i);
//      std::io::println(#fmt("%u: %c",i,c));
      i = j;
   }

   /* Output:
      0: 中
      3: 华
      6: V
      7: i
      8: ệ
      11: t
      12:
      13: N
      14: a
      15: m
   */
}

<commit_msg>ok, cleaning up my slice tests a bit..<commit_after>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

#[link(name = "str2", author = "kcantu", vers = "0.0")];
use std;

// a better slice, unicode safe
// since strings are null terminated, cannot copy in place
//
// start is the character position to begin copying
// end is the character position which should not be copied
//
// Does not make internal conversion to char (which is UTF-32/UCS-4),
// but is UTF-8 aware.
//

// helper: note, slice_chars could be faster (by not starting byte_position from zero the second time)
// if this was a named block internal to slice_chars
fn byte_position (&&ss: str, char_position: uint) -> uint
{
   let cursor_char = 0u;
   let cursor_byte = 0u;

   while cursor_char < char_position {
      let sz = str::utf8_char_width(ss[cursor_byte]);
      assert sz > 0u;
      cursor_byte += sz;
      cursor_char += 1u;
   }
   assert cursor_char <= str::char_len(ss);
   assert cursor_byte <= str::byte_len(ss);
   ret cursor_byte;
}

fn slice_chars(ss: str, begin: uint, end: uint) -> str unsafe
{
   assert begin <= end;
   assert end <= str::char_len(ss);

   // find the begin and end
   let byte_begin = byte_position(ss, begin);
//   std::io::println(#fmt("begin: %u", byte_begin));
   let byte_end   = byte_position(ss, end);
//   std::io::println(#fmt("end: %u", byte_end));

   // copy the bytes
   let new_vector = [];
   let ii = byte_begin;

   while ii < byte_end {
//      std::io::println(#fmt("pushing another u8: {%02x}", ss[ii] as uint));
      vec::push(new_vector, ss[ii]);
      ii += 1u;
   }
   vec::push(new_vector, 0u8);

   // return as a string
   let new_string: str = unsafe::reinterpret_cast(new_vector);
   unsafe::leak(new_vector);
   ret new_string;
}

#[test]
fn test_slice() {
    assert (str::eq("ab", slice_chars("abc", 0u, 2u)));
    assert (str::eq("bc", slice_chars("abc", 1u, 3u)));
    assert (str::eq("", slice_chars("abc", 1u, 1u)));
    fn a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaaaaaaa"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaa"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_a(),
                    slice_chars(a_million_letter_a(), 0u, 500000u)));
}

#[test]
fn test_slice_with_unicode_a() {
    let data = "ประเทศไทย中华Việt Nam";

    assert (str::eq("ปร", slice_chars(data, 0u, 2u)));
    assert (str::eq("ระ", slice_chars(data, 1u, 3u)));
    assert (str::eq("", slice_chars(data, 1u, 1u)));
}

#[test]
fn test_slice_with_unicode_b() {
    fn a_million_letter_X() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "华华华华华华华华华华"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_X() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "华华华华华"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_X(),
                    slice_chars(a_million_letter_X(), 0u, 500000u)));
}

#[test]
fn equals_unicode() {
   let data = "ประเทศไทย中华Việt Nam";
   let data2 = "ประเทศไทย中华Việt Nam";
   assert str::eq(data,data2);

   assert str::eq("华", "华");
   assert str::eq("华华", "华华");
}

// a more general split, unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: fn&(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a ()
{
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example ()
{
   let s = "中华Việt Nam";
   let i = 0u;
   while i < str::byte_len(s)
   {
      let {ch:c, next:j} = str::char_range_at(s, i);
      std::io::println(#fmt("%u: %c",i,c));
      i = j;
   }

   /* Output:
      0: 中
      3: 华
      6: V
      7: i
      8: ệ
      11: t
      12:
      13: N
      14: a
      15: m
   */
}

<|endoftext|>


<commit_before>//! Targets the ARMv4T, with code as `t32` code by default.
//!
//! Primarily of use for the GBA, but usable with other devices too.
//!
//! Please ping @Lokathor if changes are needed.
//!
//! This target profile assumes that you have the ARM binutils in your path (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free for all major OSes from the ARM developer's website, and they may also be available in your system's package manager. Unfortunately, the standard linker that Rust uses (`lld`) only supports as far back as `ARMv5TE`, so we must use the GNU `ld` linker.
//!
//! **Important:** This target profile **does not** specify a linker script. You just get the default link script when you build a binary for this target. The default link script is very likely wrong, so you should use `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.

use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions, TargetResult};

pub fn target() -> TargetResult {
    Ok(Target {
        llvm_target: "thumbv4t-none-eabi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: "".to_string(),
        target_vendor: "".to_string(),
        arch: "arm".to_string(),
        /* Data layout args are '-' separated:
         * little endian
         * stack is 64-bit aligned (EABI)
         * pointers are 32-bit
         * i64 must be 64-bit aligned (EABI)
         * mangle names with ELF style
         * native integers are 32-bit
         * All other elements are default
         */
        data_layout: "e-S64-p:32:32-i64:64-m:e-n32".to_string(),
        linker_flavor: LinkerFlavor::Ld,
        options: TargetOptions {
            linker: Some("arm-none-eabi-ld".to_string()),
            linker_is_gnu: true,

            // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
            // * activate t32/a32 interworking
            // * use arch ARMv4T
            // * use little-endian
            asm_args: vec![
                "-mthumb-interwork".to_string(),
                "-march=armv4t".to_string(),
                "-mlittle-endian".to_string(),
            ],

            // minimum extra features, these cannot be disabled via -C
            features: "+soft-float,+strict-align".to_string(),

            main_needs_argc_argv: false,

            // No thread-local storage (just use a static Cell)
            has_elf_tls: false,

            // don't have atomic compare-and-swap
            atomic_cas: false,

            ..super::thumb_base::opts()
        },
    })
}
<commit_msg>remove unused imports<commit_after>//! Targets the ARMv4T, with code as `t32` code by default.
//!
//! Primarily of use for the GBA, but usable with other devices too.
//!
//! Please ping @Lokathor if changes are needed.
//!
//! This target profile assumes that you have the ARM binutils in your path (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free for all major OSes from the ARM developer's website, and they may also be available in your system's package manager. Unfortunately, the standard linker that Rust uses (`lld`) only supports as far back as `ARMv5TE`, so we must use the GNU `ld` linker.
//!
//! **Important:** This target profile **does not** specify a linker script. You just get the default link script when you build a binary for this target. The default link script is very likely wrong, so you should use `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.

use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};

pub fn target() -> TargetResult {
    Ok(Target {
        llvm_target: "thumbv4t-none-eabi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: "".to_string(),
        target_vendor: "".to_string(),
        arch: "arm".to_string(),
        /* Data layout args are '-' separated:
         * little endian
         * stack is 64-bit aligned (EABI)
         * pointers are 32-bit
         * i64 must be 64-bit aligned (EABI)
         * mangle names with ELF style
         * native integers are 32-bit
         * All other elements are default
         */
        data_layout: "e-S64-p:32:32-i64:64-m:e-n32".to_string(),
        linker_flavor: LinkerFlavor::Ld,
        options: TargetOptions {
            linker: Some("arm-none-eabi-ld".to_string()),
            linker_is_gnu: true,

            // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
            // * activate t32/a32 interworking
            // * use arch ARMv4T
            // * use little-endian
            asm_args: vec![
                "-mthumb-interwork".to_string(),
                "-march=armv4t".to_string(),
                "-mlittle-endian".to_string(),
            ],

            // minimum extra features, these cannot be disabled via -C
            features: "+soft-float,+strict-align".to_string(),

            main_needs_argc_argv: false,

            // No thread-local storage (just use a static Cell)
            has_elf_tls: false,

            // don't have atomic compare-and-swap
            atomic_cas: false,

            ..super::thumb_base::opts()
        },
    })
}
<|endoftext|>