<commit_before>extern crate gcc;
extern crate tempdir;

use std::env;
use std::path::Path;
use std::process::Command;

use gcc::Config;
use tempdir::TempDir;

macro_rules! try {
    ($e:expr) => {
        $e.unwrap_or_else(|e| panic!("{} with {}", stringify!($e), e))
    }
}

fn main() {
    let td = try!(TempDir::new("compiler-rt"));
    let src = td.path();

    fetch(src);
    build(src);
}

fn fetch(td: &Path) {
    // FIXME use the `curl`, `flate2`, `tar` crates instead of shelling out to `git`.
    // FIXME Should probably use the rust-lang/compiler-rt repository
    assert!(try!(Command::new("git")
                     .args(&["clone",
                             "--depth",
                             "1",
                             "https://github.com/llvm-mirror/compiler-rt"])
                     .arg(td)
                     .status())
                .success());
}

fn build(src: &Path) {
    // FIXME(copied from compiler-rt source) atomic.c may only be compiled if host compiler
    // understands _Atomic
    const GENERIC_SOURCES: &'static [&'static str] = &["absvdi2.c",
                                                       "absvsi2.c",
                                                       "absvti2.c",
                                                       "adddf3.c",
                                                       "addsf3.c",
                                                       "addtf3.c",
                                                       "addvdi3.c",
                                                       "addvsi3.c",
                                                       "addvti3.c",
                                                       "apple_versioning.c",
                                                       "ashldi3.c",
                                                       "ashlti3.c",
                                                       "ashrdi3.c",
                                                       "ashrti3.c",
                                                       // "atomic.c",
                                                       "clear_cache.c",
                                                       "clzdi2.c",
                                                       "clzsi2.c",
                                                       "clzti2.c",
                                                       "cmpdi2.c",
                                                       "cmpti2.c",
                                                       "comparedf2.c",
                                                       "comparesf2.c",
                                                       "ctzdi2.c",
                                                       "ctzsi2.c",
                                                       "ctzti2.c",
                                                       "divdc3.c",
                                                       "divdf3.c",
                                                       "divdi3.c",
                                                       "divmoddi4.c",
                                                       "divmodsi4.c",
                                                       "divsc3.c",
                                                       "divsf3.c",
                                                       "divsi3.c",
                                                       "divtc3.c",
                                                       "divti3.c",
                                                       "divtf3.c",
                                                       "divxc3.c",
                                                       "enable_execute_stack.c",
                                                       "eprintf.c",
                                                       "extendsfdf2.c",
                                                       "extendhfsf2.c",
                                                       "ffsdi2.c",
                                                       "ffsti2.c",
                                                       "fixdfdi.c",
                                                       "fixdfsi.c",
                                                       "fixdfti.c",
                                                       "fixsfdi.c",
                                                       "fixsfsi.c",
                                                       "fixsfti.c",
                                                       "fixunsdfdi.c",
                                                       "fixunsdfsi.c",
                                                       "fixunsdfti.c",
                                                       "fixunssfdi.c",
                                                       "fixunssfsi.c",
                                                       "fixunssfti.c",
                                                       "fixunsxfdi.c",
                                                       "fixunsxfsi.c",
                                                       "fixunsxfti.c",
                                                       "fixxfdi.c",
                                                       "fixxfti.c",
                                                       "floatdidf.c",
                                                       "floatdisf.c",
                                                       "floatdixf.c",
                                                       "floatsidf.c",
                                                       "floatsisf.c",
                                                       "floattidf.c",
                                                       "floattisf.c",
                                                       "floattixf.c",
                                                       "floatundidf.c",
                                                       "floatundisf.c",
                                                       "floatundixf.c",
                                                       "floatunsidf.c",
                                                       "floatunsisf.c",
                                                       "floatuntidf.c",
                                                       "floatuntisf.c",
                                                       "floatuntixf.c",
                                                       "int_util.c",
                                                       "lshrdi3.c",
                                                       "lshrti3.c",
                                                       "moddi3.c",
                                                       "modsi3.c",
                                                       "modti3.c",
                                                       "muldc3.c",
                                                       "muldf3.c",
                                                       "muldi3.c",
                                                       "mulodi4.c",
                                                       "mulosi4.c",
                                                       "muloti4.c",
                                                       "mulsc3.c",
                                                       "mulsf3.c",
                                                       "multi3.c",
                                                       "multf3.c",
                                                       "mulvdi3.c",
                                                       "mulvsi3.c",
                                                       "mulvti3.c",
                                                       "mulxc3.c",
                                                       "negdf2.c",
                                                       "negdi2.c",
                                                       "negsf2.c",
                                                       "negti2.c",
                                                       "negvdi2.c",
                                                       "negvsi2.c",
                                                       "negvti2.c",
                                                       "paritydi2.c",
                                                       "paritysi2.c",
                                                       "parityti2.c",
                                                       "popcountdi2.c",
                                                       "popcountsi2.c",
                                                       "popcountti2.c",
                                                       "powidf2.c",
                                                       "powisf2.c",
                                                       "powitf2.c",
                                                       "powixf2.c",
                                                       "subdf3.c",
                                                       "subsf3.c",
                                                       "subvdi3.c",
                                                       "subvsi3.c",
                                                       "subvti3.c",
                                                       "subtf3.c",
                                                       "trampoline_setup.c",
                                                       "truncdfhf2.c",
                                                       "truncdfsf2.c",
                                                       "truncsfhf2.c",
                                                       "ucmpdi2.c",
                                                       "ucmpti2.c",
                                                       "udivdi3.c",
                                                       "udivmoddi4.c",
                                                       "udivmodsi4.c",
                                                       "udivmodti4.c",
                                                       "udivsi3.c",
                                                       "udivti3.c",
                                                       "umoddi3.c",
                                                       "umodsi3.c",
                                                       "umodti3.c"];

    const ARM_SOURCES: &'static [&'static str] = &["arm/adddf3vfp.S",
                                                   "arm/addsf3vfp.S",
                                                   "arm/aeabi_cdcmp.S",
                                                   "arm/aeabi_cdcmpeq_check_nan.c",
                                                   "arm/aeabi_cfcmp.S",
                                                   "arm/aeabi_cfcmpeq_check_nan.c",
                                                   "arm/aeabi_dcmp.S",
                                                   "arm/aeabi_div0.c",
                                                   "arm/aeabi_drsub.c",
                                                   "arm/aeabi_fcmp.S",
                                                   "arm/aeabi_frsub.c",
                                                   "arm/aeabi_idivmod.S",
                                                   "arm/aeabi_ldivmod.S",
                                                   "arm/aeabi_memcmp.S",
                                                   "arm/aeabi_memcpy.S",
                                                   "arm/aeabi_memmove.S",
                                                   "arm/aeabi_memset.S",
                                                   "arm/aeabi_uidivmod.S",
                                                   "arm/aeabi_uldivmod.S",
                                                   "arm/bswapdi2.S",
                                                   "arm/bswapsi2.S",
                                                   "arm/clzdi2.S",
                                                   "arm/clzsi2.S",
                                                   "arm/comparesf2.S",
                                                   "arm/divdf3vfp.S",
                                                   "arm/divmodsi4.S",
                                                   "arm/divsf3vfp.S",
                                                   "arm/divsi3.S",
                                                   "arm/eqdf2vfp.S",
                                                   "arm/eqsf2vfp.S",
                                                   "arm/extendsfdf2vfp.S",
                                                   "arm/fixdfsivfp.S",
                                                   "arm/fixsfsivfp.S",
                                                   "arm/fixunsdfsivfp.S",
                                                   "arm/fixunssfsivfp.S",
                                                   "arm/floatsidfvfp.S",
                                                   "arm/floatsisfvfp.S",
                                                   "arm/floatunssidfvfp.S",
                                                   "arm/floatunssisfvfp.S",
                                                   "arm/gedf2vfp.S",
                                                   "arm/gesf2vfp.S",
                                                   "arm/gtdf2vfp.S",
                                                   "arm/gtsf2vfp.S",
                                                   "arm/ledf2vfp.S",
                                                   "arm/lesf2vfp.S",
                                                   "arm/ltdf2vfp.S",
                                                   "arm/ltsf2vfp.S",
                                                   "arm/modsi3.S",
                                                   "arm/muldf3vfp.S",
                                                   "arm/mulsf3vfp.S",
                                                   "arm/nedf2vfp.S",
                                                   "arm/negdf2vfp.S",
                                                   "arm/negsf2vfp.S",
                                                   "arm/nesf2vfp.S",
                                                   "arm/restore_vfp_d8_d15_regs.S",
                                                   "arm/save_vfp_d8_d15_regs.S",
                                                   "arm/subdf3vfp.S",
                                                   "arm/subsf3vfp.S",
                                                   "arm/switch16.S",
                                                   "arm/switch32.S",
                                                   "arm/switch8.S",
                                                   "arm/switchu8.S",
                                                   "arm/sync_fetch_and_add_4.S",
                                                   "arm/sync_fetch_and_add_8.S",
                                                   "arm/sync_fetch_and_and_4.S",
                                                   "arm/sync_fetch_and_and_8.S",
                                                   "arm/sync_fetch_and_max_4.S",
                                                   "arm/sync_fetch_and_max_8.S",
                                                   "arm/sync_fetch_and_min_4.S",
                                                   "arm/sync_fetch_and_min_8.S",
                                                   "arm/sync_fetch_and_nand_4.S",
                                                   "arm/sync_fetch_and_nand_8.S",
                                                   "arm/sync_fetch_and_or_4.S",
                                                   "arm/sync_fetch_and_or_8.S",
                                                   "arm/sync_fetch_and_sub_4.S",
                                                   "arm/sync_fetch_and_sub_8.S",
                                                   "arm/sync_fetch_and_umax_4.S",
                                                   "arm/sync_fetch_and_umax_8.S",
                                                   "arm/sync_fetch_and_umin_4.S",
                                                   "arm/sync_fetch_and_umin_8.S",
                                                   "arm/sync_fetch_and_xor_4.S",
                                                   "arm/sync_fetch_and_xor_8.S",
                                                   "arm/sync_synchronize.S",
                                                   "arm/truncdfsf2vfp.S",
                                                   "arm/udivmodsi4.S",
                                                   "arm/udivsi3.S",
                                                   "arm/umodsi3.S",
                                                   "arm/unorddf2vfp.S",
                                                   "arm/unordsf2vfp.S"];

    const OS_NONE_BLACKLIST: &'static [&'static str] = &["enable_execute_stack.c"];

    const NON_HF_BLACKLIST: &'static [&'static str] = &["arm/adddf3vfp.S",
                                                        "arm/addsf3vfp.S",
                                                        "arm/divdf3vfp.S",
                                                        "arm/divsf3vfp.S",
                                                        "arm/eqdf2vfp.S",
                                                        "arm/eqsf2vfp.S",
                                                        "arm/extendsfdf2vfp.S",
                                                        "arm/fixdfsivfp.S",
                                                        "arm/fixdfsivfp.S",
                                                        "arm/fixsfsivfp.S",
                                                        "arm/fixunsdfsivfp.S",
                                                        "arm/fixunssfsivfp.S",
                                                        "arm/floatsidfvfp.S",
                                                        "arm/floatsisfvfp.S",
                                                        "arm/floatunssidfvfp.S",
                                                        "arm/floatunssisfvfp.S",
                                                        "arm/gedf2vfp.S",
                                                        "arm/gesf2vfp.S",
                                                        "arm/gtdf2vfp.S",
                                                        "arm/gtsf2vfp.S",
                                                        "arm/ledf2vfp.S",
                                                        "arm/lesf2vfp.S",
                                                        "arm/ltdf2vfp.S",
                                                        "arm/ltsf2vfp.S",
                                                        "arm/muldf3vfp.S",
                                                        "arm/mulsf3vfp.S",
                                                        "arm/nedf2vfp.S",
                                                        "arm/nesf2vfp.S",
                                                        "arm/restore_vfp_d8_d15_regs.S",
                                                        "arm/save_vfp_d8_d15_regs.S",
                                                        "arm/subdf3vfp.S",
                                                        "arm/subsf3vfp.S",
                                                        "arm/truncdfsf2vfp.S",
                                                        "arm/unorddf2vfp.S",
                                                        "arm/unordsf2vfp.S"];

    // FIXME Instead of `$TARGET` I want to use the target's `llvm-target` field but, currently,
    // there's no way to do that AFAICT. It would be also helpful if I could access the target's
    // `os` and `arch` fields.
    let target = try!(env::var("TARGET"));
    let mut config = Config::new();
    for source in GENERIC_SOURCES {
        if target.contains("none") {
            if !OS_NONE_BLACKLIST.contains(source) {
                config.file(src.join("lib/builtins").join(source));
            }
        } else {
            config.file(src.join("lib/builtins").join(source));
        }
    }
    if target.starts_with("arm") || target.starts_with("thumb") {
        for source in ARM_SOURCES {
            if !target.ends_with("hf") {
                if !NON_HF_BLACKLIST.contains(source) {
                    config.file(src.join("lib/builtins").join(source));
                }
            } else {
                config.file(src.join("lib/builtins").join(source));
            }
        }
    }
    config.compile("libcompiler-rt.a");
}
<commit_msg>assert that AR and CC are set by the user<commit_after>extern crate gcc;
extern crate tempdir;

use std::env;
use std::path::Path;
use std::process::Command;

use gcc::Config;
use tempdir::TempDir;

macro_rules! try {
    ($e:expr) => {
        $e.unwrap_or_else(|e| panic!("{} with {}", stringify!($e), e))
    }
}

fn main() {
    // FIXME Instead of `$TARGET` I want to use the target's `llvm-target` field but, currently,
    // there's no way to do that AFAICT. It would be also helpful if I could access the target's
    // `os` and `arch` fields.
    let target = &try!(env::var("TARGET"));
    let target_ = target.replace("-", "_");

    must_exist(&format!("AR_{}", target_));
    must_exist(&format!("CC_{}", target_));

    let td = try!(TempDir::new("compiler-rt"));
    let src = td.path();

    fetch(src);
    build(src, target);
}

fn must_exist(var: &str) {
    if env::var_os(var).is_none() {
        panic!("{} not set", var);
    }
}

fn fetch(td: &Path) {
    // FIXME use the `curl`, `flate2`, `tar` crates instead of shelling out to `git`.
    // FIXME Should probably use the rust-lang/compiler-rt repository
    assert!(try!(Command::new("git")
                     .args(&["clone",
                             "--depth",
                             "1",
                             "https://github.com/llvm-mirror/compiler-rt"])
                     .arg(td)
                     .status())
                .success());
}

fn build(src: &Path, target: &str) {
    // FIXME(copied from compiler-rt source) atomic.c may only be compiled if host compiler
    // understands _Atomic
    const GENERIC_SOURCES: &'static [&'static str] = &["absvdi2.c",
                                                       "absvsi2.c",
                                                       "absvti2.c",
                                                       "adddf3.c",
                                                       "addsf3.c",
                                                       "addtf3.c",
                                                       "addvdi3.c",
                                                       "addvsi3.c",
                                                       "addvti3.c",
                                                       "apple_versioning.c",
                                                       "ashldi3.c",
                                                       "ashlti3.c",
                                                       "ashrdi3.c",
                                                       "ashrti3.c",
                                                       // "atomic.c",
                                                       "clear_cache.c",
                                                       "clzdi2.c",
                                                       "clzsi2.c",
                                                       "clzti2.c",
                                                       "cmpdi2.c",
                                                       "cmpti2.c",
                                                       "comparedf2.c",
                                                       "comparesf2.c",
                                                       "ctzdi2.c",
                                                       "ctzsi2.c",
                                                       "ctzti2.c",
                                                       "divdc3.c",
                                                       "divdf3.c",
                                                       "divdi3.c",
                                                       "divmoddi4.c",
                                                       "divmodsi4.c",
                                                       "divsc3.c",
                                                       "divsf3.c",
                                                       "divsi3.c",
                                                       "divtc3.c",
                                                       "divti3.c",
                                                       "divtf3.c",
                                                       "divxc3.c",
                                                       "enable_execute_stack.c",
                                                       "eprintf.c",
                                                       "extendsfdf2.c",
                                                       "extendhfsf2.c",
                                                       "ffsdi2.c",
                                                       "ffsti2.c",
                                                       "fixdfdi.c",
                                                       "fixdfsi.c",
                                                       "fixdfti.c",
                                                       "fixsfdi.c",
                                                       "fixsfsi.c",
                                                       "fixsfti.c",
                                                       "fixunsdfdi.c",
                                                       "fixunsdfsi.c",
                                                       "fixunsdfti.c",
                                                       "fixunssfdi.c",
                                                       "fixunssfsi.c",
                                                       "fixunssfti.c",
                                                       "fixunsxfdi.c",
                                                       "fixunsxfsi.c",
                                                       "fixunsxfti.c",
                                                       "fixxfdi.c",
                                                       "fixxfti.c",
                                                       "floatdidf.c",
                                                       "floatdisf.c",
                                                       "floatdixf.c",
                                                       "floatsidf.c",
                                                       "floatsisf.c",
                                                       "floattidf.c",
                                                       "floattisf.c",
                                                       "floattixf.c",
                                                       "floatundidf.c",
                                                       "floatundisf.c",
                                                       "floatundixf.c",
                                                       "floatunsidf.c",
                                                       "floatunsisf.c",
                                                       "floatuntidf.c",
                                                       "floatuntisf.c",
                                                       "floatuntixf.c",
                                                       "int_util.c",
                                                       "lshrdi3.c",
                                                       "lshrti3.c",
                                                       "moddi3.c",
                                                       "modsi3.c",
                                                       "modti3.c",
                                                       "muldc3.c",
                                                       "muldf3.c",
                                                       "muldi3.c",
                                                       "mulodi4.c",
                                                       "mulosi4.c",
                                                       "muloti4.c",
                                                       "mulsc3.c",
                                                       "mulsf3.c",
                                                       "multi3.c",
                                                       "multf3.c",
                                                       "mulvdi3.c",
                                                       "mulvsi3.c",
                                                       "mulvti3.c",
                                                       "mulxc3.c",
                                                       "negdf2.c",
                                                       "negdi2.c",
                                                       "negsf2.c",
                                                       "negti2.c",
                                                       "negvdi2.c",
                                                       "negvsi2.c",
                                                       "negvti2.c",
                                                       "paritydi2.c",
                                                       "paritysi2.c",
                                                       "parityti2.c",
                                                       "popcountdi2.c",
                                                       "popcountsi2.c",
                                                       "popcountti2.c",
                                                       "powidf2.c",
                                                       "powisf2.c",
                                                       "powitf2.c",
                                                       "powixf2.c",
                                                       "subdf3.c",
                                                       "subsf3.c",
                                                       "subvdi3.c",
                                                       "subvsi3.c",
                                                       "subvti3.c",
                                                       "subtf3.c",
                                                       "trampoline_setup.c",
                                                       "truncdfhf2.c",
                                                       "truncdfsf2.c",
                                                       "truncsfhf2.c",
                                                       "ucmpdi2.c",
                                                       "ucmpti2.c",
                                                       "udivdi3.c",
                                                       "udivmoddi4.c",
                                                       "udivmodsi4.c",
                                                       "udivmodti4.c",
                                                       "udivsi3.c",
                                                       "udivti3.c",
                                                       "umoddi3.c",
                                                       "umodsi3.c",
                                                       "umodti3.c"];

    const ARM_SOURCES: &'static [&'static str] = &["arm/adddf3vfp.S",
                                                   "arm/addsf3vfp.S",
                                                   "arm/aeabi_cdcmp.S",
                                                   "arm/aeabi_cdcmpeq_check_nan.c",
                                                   "arm/aeabi_cfcmp.S",
                                                   "arm/aeabi_cfcmpeq_check_nan.c",
                                                   "arm/aeabi_dcmp.S",
                                                   "arm/aeabi_div0.c",
                                                   "arm/aeabi_drsub.c",
                                                   "arm/aeabi_fcmp.S",
                                                   "arm/aeabi_frsub.c",
                                                   "arm/aeabi_idivmod.S",
                                                   "arm/aeabi_ldivmod.S",
                                                   "arm/aeabi_memcmp.S",
                                                   "arm/aeabi_memcpy.S",
                                                   "arm/aeabi_memmove.S",
                                                   "arm/aeabi_memset.S",
                                                   "arm/aeabi_uidivmod.S",
                                                   "arm/aeabi_uldivmod.S",
                                                   "arm/bswapdi2.S",
                                                   "arm/bswapsi2.S",
                                                   "arm/clzdi2.S",
                                                   "arm/clzsi2.S",
                                                   "arm/comparesf2.S",
                                                   "arm/divdf3vfp.S",
                                                   "arm/divmodsi4.S",
                                                   "arm/divsf3vfp.S",
                                                   "arm/divsi3.S",
                                                   "arm/eqdf2vfp.S",
                                                   "arm/eqsf2vfp.S",
                                                   "arm/extendsfdf2vfp.S",
                                                   "arm/fixdfsivfp.S",
                                                   "arm/fixsfsivfp.S",
                                                   "arm/fixunsdfsivfp.S",
                                                   "arm/fixunssfsivfp.S",
                                                   "arm/floatsidfvfp.S",
                                                   "arm/floatsisfvfp.S",
                                                   "arm/floatunssidfvfp.S",
                                                   "arm/floatunssisfvfp.S",
                                                   "arm/gedf2vfp.S",
                                                   "arm/gesf2vfp.S",
                                                   "arm/gtdf2vfp.S",
                                                   "arm/gtsf2vfp.S",
                                                   "arm/ledf2vfp.S",
                                                   "arm/lesf2vfp.S",
                                                   "arm/ltdf2vfp.S",
                                                   "arm/ltsf2vfp.S",
                                                   "arm/modsi3.S",
                                                   "arm/muldf3vfp.S",
                                                   "arm/mulsf3vfp.S",
                                                   "arm/nedf2vfp.S",
                                                   "arm/negdf2vfp.S",
                                                   "arm/negsf2vfp.S",
                                                   "arm/nesf2vfp.S",
                                                   "arm/restore_vfp_d8_d15_regs.S",
                                                   "arm/save_vfp_d8_d15_regs.S",
                                                   "arm/subdf3vfp.S",
                                                   "arm/subsf3vfp.S",
                                                   "arm/switch16.S",
                                                   "arm/switch32.S",
                                                   "arm/switch8.S",
                                                   "arm/switchu8.S",
                                                   "arm/sync_fetch_and_add_4.S",
                                                   "arm/sync_fetch_and_add_8.S",
                                                   "arm/sync_fetch_and_and_4.S",
                                                   "arm/sync_fetch_and_and_8.S",
                                                   "arm/sync_fetch_and_max_4.S",
                                                   "arm/sync_fetch_and_max_8.S",
                                                   "arm/sync_fetch_and_min_4.S",
                                                   "arm/sync_fetch_and_min_8.S",
                                                   "arm/sync_fetch_and_nand_4.S",
                                                   "arm/sync_fetch_and_nand_8.S",
                                                   "arm/sync_fetch_and_or_4.S",
                                                   "arm/sync_fetch_and_or_8.S",
                                                   "arm/sync_fetch_and_sub_4.S",
                                                   "arm/sync_fetch_and_sub_8.S",
                                                   "arm/sync_fetch_and_umax_4.S",
                                                   "arm/sync_fetch_and_umax_8.S",
                                                   "arm/sync_fetch_and_umin_4.S",
                                                   "arm/sync_fetch_and_umin_8.S",
                                                   "arm/sync_fetch_and_xor_4.S",
                                                   "arm/sync_fetch_and_xor_8.S",
                                                   "arm/sync_synchronize.S",
                                                   "arm/truncdfsf2vfp.S",
                                                   "arm/udivmodsi4.S",
                                                   "arm/udivsi3.S",
                                                   "arm/umodsi3.S",
                                                   "arm/unorddf2vfp.S",
                                                   "arm/unordsf2vfp.S"];

    const OS_NONE_BLACKLIST: &'static [&'static str] = &["enable_execute_stack.c"];

    const NON_HF_BLACKLIST: &'static [&'static str] = &["arm/adddf3vfp.S",
                                                        "arm/addsf3vfp.S",
                                                        "arm/divdf3vfp.S",
                                                        "arm/divsf3vfp.S",
                                                        "arm/eqdf2vfp.S",
                                                        "arm/eqsf2vfp.S",
                                                        "arm/extendsfdf2vfp.S",
                                                        "arm/fixdfsivfp.S",
                                                        "arm/fixdfsivfp.S",
                                                        "arm/fixsfsivfp.S",
                                                        "arm/fixunsdfsivfp.S",
                                                        "arm/fixunssfsivfp.S",
                                                        "arm/floatsidfvfp.S",
                                                        "arm/floatsisfvfp.S",
                                                        "arm/floatunssidfvfp.S",
                                                        "arm/floatunssisfvfp.S",
                                                        "arm/gedf2vfp.S",
                                                        "arm/gesf2vfp.S",
                                                        "arm/gtdf2vfp.S",
                                                        "arm/gtsf2vfp.S",
                                                        "arm/ledf2vfp.S",
                                                        "arm/lesf2vfp.S",
                                                        "arm/ltdf2vfp.S",
                                                        "arm/ltsf2vfp.S",
                                                        "arm/muldf3vfp.S",
                                                        "arm/mulsf3vfp.S",
                                                        "arm/nedf2vfp.S",
                                                        "arm/nesf2vfp.S",
                                                        "arm/restore_vfp_d8_d15_regs.S",
                                                        "arm/save_vfp_d8_d15_regs.S",
                                                        "arm/subdf3vfp.S",
                                                        "arm/subsf3vfp.S",
                                                        "arm/truncdfsf2vfp.S",
                                                        "arm/unorddf2vfp.S",
                                                        "arm/unordsf2vfp.S"];

    let mut config = Config::new();
    for source in GENERIC_SOURCES {
        if target.contains("none") {
            if !OS_NONE_BLACKLIST.contains(source) {
                config.file(src.join("lib/builtins").join(source));
            }
        } else {
            config.file(src.join("lib/builtins").join(source));
        }
    }
    if target.starts_with("arm") || target.starts_with("thumb") {
        for source in ARM_SOURCES {
            if !target.ends_with("hf") {
                if !NON_HF_BLACKLIST.contains(source) {
                    config.file(src.join("lib/builtins").join(source));
                }
            } else {
                config.file(src.join("lib/builtins").join(source));
            }
        }
    }
    config.compile("libcompiler-rt.a");
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str;

fn main() {
    let rustc_minor_ver =
        rustc_minor_version().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    if env::var("LIBC_CI").is_ok() {
        if let Some(11) = which_freebsd() {
            println!("cargo:rustc-cfg=freebsd11");
        }
        if let Some(12) = which_freebsd() {
            println!("cargo:rustc-cfg=freebsd12");
        }
        if let Some(13) = which_freebsd() {
            println!("cargo:rustc-cfg=freebsd13");
        }
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N))
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }
}

fn rustc_minor_version() -> Option<u32> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    otry!(pieces.next()).parse().ok()
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        _ => None,
    }
}
<commit_msg>Fix FreeBSD build<commit_after>use std::env;
use std::process::Command;
use std::str;

fn main() {
    let rustc_minor_ver =
        rustc_minor_version().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    #[allow(unused)]
    let libc_ci = env::var("LIBC_CI").is_ok();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    #[cfg(target_os = "freebsd")]
    match which_freebsd() {
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(_) => println!("cargo:rustc-cfg=freebsd11"),
        None =>
        /* not FreeBSD - nothing to do here */
        {
            ()
        }
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N))
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }
}

fn rustc_minor_version() -> Option<u32> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    otry!(pieces.next()).parse().ok()
}

#[cfg(target_os = "freebsd")]
fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        _ => None,
    }
}
<|endoftext|>


<commit_before>// extern crate gcc;

use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let target = env::var("TARGET").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, _, os, compiler) = (target_quad[0], target_quad[1], target_quad[2], target_quad[3]);
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    // Windows
    if os == "windows" {
        // Currently only supporting mingw
        if compiler != "gnu" {
            panic!("Unsupported compiler");
        }

        // projects
        {
            Command::new("make.exe")
                .current_dir("bgfx")
                .arg(".build/projects/gmake-mingw-gcc")
                .output()
                .unwrap();
        }

        // lib
        {
            Command::new("make.exe")
                .current_dir("bgfx")
                .arg("-R")
                .arg("-C")
                .arg(".build/projects/gmake-mingw-gcc")
                .arg(format!("config=release{}", bitness))
                .arg("bgfx")
                .output()
                .unwrap();
        }

        // link config
        {
            let mut path = PathBuf::from(env::current_dir().unwrap());
            path.push("bgfx");
            path.push(".build");
            path.push(format!("win{}_mingw-gcc", bitness));
            path.push("bin");

            println!("cargo:rustc-link-lib=static=bgfxRelease");
            println!("cargo:rustc-link-search={}", path.as_os_str().to_str().unwrap());
        }
    }
}
<commit_msg>Removing old comment<commit_after>use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let target = env::var("TARGET").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, _, os, compiler) = (target_quad[0], target_quad[1], target_quad[2], target_quad[3]);
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    // Windows
    if os == "windows" {
        // Currently only supporting mingw
        if compiler != "gnu" {
            panic!("Unsupported compiler");
        }

        // projects
        {
            Command::new("make.exe")
                .current_dir("bgfx")
                .arg(".build/projects/gmake-mingw-gcc")
                .output()
                .unwrap();
        }

        // lib
        {
            Command::new("make.exe")
                .current_dir("bgfx")
                .arg("-R")
                .arg("-C")
                .arg(".build/projects/gmake-mingw-gcc")
                .arg(format!("config=release{}", bitness))
                .arg("bgfx")
                .output()
                .unwrap();
        }

        // link config
        {
            let mut path = PathBuf::from(env::current_dir().unwrap());
            path.push("bgfx");
            path.push(".build");
            path.push(format!("win{}_mingw-gcc", bitness));
            path.push("bin");

            println!("cargo:rustc-link-lib=static=bgfxRelease");
            println!("cargo:rustc-link-search={}", path.as_os_str().to_str().unwrap());
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    if std::env::var("CARGO_FEATURE_STATIC").is_ok() {
        let static_path = std::env::var("ODBC_SYS_STATIC_PATH").unwrap_or("/usr/lib".to_string());
        println!("cargo:rerun-if-env-changed=ODBC_SYS_STATIC_PATH");
        println!("cargo:rustc-link-search=native={}", static_path);
        println!("cargo:rustc-link-lib=static=odbc");
        if cfg!(not(target_os = "windows")) {
            println!("cargo:rustc-link-lib=static=ltdl");
        }
    }

    if cfg!(target_os = "macos") {
        // if we're on Mac OS X we'll kindly add DYLD_LIBRARY_PATH to rustc's
        // linker search path
        if let Some(dyld_paths) = option_env!("DYLD_LIBRARY_PATH") {
            print_paths(dyld_paths);
        }
        // if we're on Mac OS X we'll kindly add DYLD_FALLBACK_LIBRARY_PATH to rustc's
        // linker search path
        if let Some(dyld_fallback_paths) = option_env!("DYLD_FALLBACK_LIBRARY_PATH") {
            print_paths(dyld_fallback_paths);
        }
    }
}

fn print_paths(paths: &str) {
    for path in paths.split(':').filter(|x| !x.is_empty()) {
        println!("cargo:rustc-link-search=native={}", path)
    }
}
<commit_msg>Add dynamic iconv to the OS X static build<commit_after>fn main() {
    if std::env::var("CARGO_FEATURE_STATIC").is_ok() {
        let static_path = std::env::var("ODBC_SYS_STATIC_PATH").unwrap_or("/usr/lib".to_string());
        println!("cargo:rerun-if-env-changed=ODBC_SYS_STATIC_PATH");
        println!("cargo:rustc-link-search=native={}", static_path);
        println!("cargo:rustc-link-lib=static=odbc");
        if cfg!(not(target_os = "windows")) {
            println!("cargo:rustc-link-lib=static=ltdl");
        }
        if cfg!(target_os = "macos") {
            // Homebrew's unixodbc uses the system iconv, so we can't do a fully static linking
            // but this way we at least have only dependencies on built-in libraries
            // See also https://github.com/Homebrew/homebrew-core/pull/46145
            println!("cargo:rustc-link-lib=dylib=iconv");
        }
    }

    if cfg!(target_os = "macos") {
        // if we're on Mac OS X we'll kindly add DYLD_LIBRARY_PATH to rustc's
        // linker search path
        if let Some(dyld_paths) = option_env!("DYLD_LIBRARY_PATH") {
            print_paths(dyld_paths);
        }
        // if we're on Mac OS X we'll kindly add DYLD_FALLBACK_LIBRARY_PATH to rustc's
        // linker search path
        if let Some(dyld_fallback_paths) = option_env!("DYLD_FALLBACK_LIBRARY_PATH") {
            print_paths(dyld_fallback_paths);
        }
    }
}

fn print_paths(paths: &str) {
    for path in paths.split(':').filter(|x| !x.is_empty()) {
        println!("cargo:rustc-link-search=native={}", path)
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use chrono::Utc;
use rss::{CategoryBuilder, ChannelBuilder, ItemBuilder};

use crate::Entry;

#[inline]
pub fn write<W: Write>(w: &mut W, entries: Vec<Entry<'_>>) -> Result<()> {
    let mut items = Vec::new();
    for entry in entries {
        items.push(
            ItemBuilder::default()
                .title(Some(String::from(entry.title)))
                .author(Some("PoiScript".to_owned()))
                .categories(
                    entry
                        .tags
                        .split_whitespace()
                        .map(|tag| CategoryBuilder::default().name(tag).build().unwrap())
                        .collect::<Vec<_>>(),
                )
                .description(Some(entry.content))
                .build()
                .unwrap(),
        )
    }

    ChannelBuilder::default()
        .title("solomon")
        .link("https://blog.poi.cat")
        .description("PoiScript's Blog")
        .language(Some("zh-Hans".to_owned()))
        .pub_date(Some(Utc::now().to_rfc2822()))
        .items(items)
        .build()
        .unwrap()
        .write_to(w)
        .unwrap();

    Ok(())
}
<commit_msg>feat(gen): write rss string directly<commit_after>use std::io::Write;

use chrono::Utc;

use crate::{Entry, render};
use crate::error::Result;

pub fn write<W: Write>(w: &mut W, entries: &Vec<Entry<'_>>) -> Result<()> {
    write!(
        w,
        "<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \
         xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" \
         xmlns:atom=\"http://www.w3.org/2005/Atom\" version=\"2.0\">"
    )?;
    write!(w, "<channel>")?;
    write!(w, "<title>solomon</title>")?;
    write!(w, "<description>PoiScript's Blog</description>")?;
    write!(w, "<link>https://blog.poi.cat</link>")?;
    write!(
        w,
        "<generator>solomon {}</generator>",
        env!("CARGO_PKG_VERSION")
    )?;
    write!(
        w,
        "<lastBuildDate>{}</lastBuildDate>",
        Utc::now().to_rfc2822()
    )?;
    write!(w, r#"<atom:link href="https://blog.poi.cat/atom.xml" rel="self" type="application/rss+xml"/>"#)?;
    write!(w, "<language>zh-Hans</language>")?;
    write!(
        w,
        "<copyright>Content licensed under CC-BY-SA-4.0.</copyright>"
    )?;

    for e in entries {
        render::rss(e, w)?;
    }

    write!(w, "</channel></rss>")?;

    Ok(())
}
<|endoftext|>


<commit_before>#![allow(unused_variables, dead_code)]
#[macro_use]
extern crate r2pipe;
extern crate docopt;
extern crate rustc_serialize;
extern crate radeco_lib;
//extern crate core;

mod radeco;
mod structs;

use rustc_serialize::json;
use docopt::Docopt;
use std::process::exit;
use std::fs::{File};
use std::io::{Write, Read};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_output: String,
    flag_version: bool,
    flag_shell: bool,
	flag_help: bool,
    arg_file: Option<String>,
	flag_from_json: bool,
	flag_json_builder: bool,
	cmd_run: bool,
}

static USAGE: &'static str = "
radeco. The radare2 decompiler.

Usage:
  radeco <file>
  radeco [options]
  radeco run [options] [<file>]
  radeco --shell <file>
  radeco --output=<output> <file>
  radeco --version

Options:
  --help                 Show this screen.
  --version              Show version.
  --shell                Run interactive prompt.
  --output=<mode>        Select output mode.
  --from-json            Run radeco based on config and information
                         from input json file. Needs an input file.
  --json-builder         Interactive shell used to build the config
                         json for radeco. When used with run, the
                         config generated is automatically used to
                         run radeco rather than dumping it to a file.
";

fn spawn_shell(bname: String) -> i32 {
	radeco::spawn_shell(bname)
}

//fn radeco_pipe(args:&Args) -> i32 {
	//let mut r = Radeco::pipe().unwrap();
	//if args.flag_shell {
		//r.shell();
	//} else {
		//println!("Running radeco via pipe");
		//// TODO get offset, function, bin info, ..
	//}
	//r.close();
	//0
//}

fn write_file(fname: String, res: String) {
	let mut file = File::create(fname).unwrap();
	file.write_all(res.as_bytes()).unwrap();
}

fn json_builder(run: bool) {
	let inp = structs::input_builder();
	let mut runner = inp.validate().unwrap();
	if !run {
		let mut name = inp.name.clone().unwrap();
		let json = json::as_pretty_json(&inp);
		let raw_json = format!("{}", json);
		name.push_str(".json");
		write_file(name, raw_json);
	} else {
		runner.run();
		runner.dump();
	}
}

fn read_json(fname: String) -> structs::Input {
	let mut raw_json = String::new();
	let _ = File::open(fname).unwrap().read_to_string(&mut raw_json);
	json::decode(&*raw_json).unwrap()
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    if args.flag_version {
        println!("Version: {:?}", VERSION);
        exit(0);
    }

	if args.flag_help {
		println!("{}", USAGE);
		exit(0);
	}

    //if args.arg_file != "" {
        //if args.arg_file == "-" {
            //exit(radeco_pipe(&args));
        //} else {
            //exit(radeco_file(&args));
        //}
    //}

	if args.flag_json_builder {
		json_builder(args.cmd_run);
	}

	if args.flag_from_json {
		if args.arg_file.is_none() {
			println!("{}", USAGE);
		}

		let inp = read_json(args.arg_file.clone().unwrap());
		let mut runner = inp.validate().unwrap();
		runner.run();
		runner.dump();
	}

	if args.flag_shell {
		if args.arg_file.is_none() {
			println!("{}", USAGE);
			exit(0);
		}
		let status = spawn_shell(args.arg_file.clone().unwrap());
		exit(status);
	}
}
<commit_msg>Add --verbose flag and reindent with tabs<commit_after>#![allow(unused_variables, dead_code)]
#[macro_use]
extern crate r2pipe;
extern crate docopt;
extern crate rustc_serialize;
extern crate radeco_lib;
//extern crate core;

mod radeco;
mod structs;

use rustc_serialize::json;
use docopt::Docopt;
use std::process::exit;
use std::fs::{File};
use std::io::{Write, Read};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(Debug, RustcDecodable)]
struct Args {
	flag_output: String,
	flag_version: bool,
	flag_verbose: bool,
	flag_shell: bool,
	flag_help: bool,
	arg_file: Option<String>,
	flag_from_json: bool,
	flag_json_builder: bool,
	cmd_run: bool,
}

static USAGE: &'static str = "
radeco. The radare2 decompiler.

Usage:
  radeco <file>
  radeco [options] [<file>]
  radeco run [options] [<file>]
  radeco --shell <file>
  radeco --output=<output> <file>
  radeco --version
  radeco --verbose

Options:
  --help                 Show this screen.
  --version              Show version.
  --verbose              Display verbose output.
  --shell                Run interactive prompt.
  --output=<mode>        Select output mode.
  --from-json            Run radeco based on config and information
                         from input json file. Needs an input file.
  --json-builder         Interactive wizard to build the JSON config
                         file needed for radeco. When used with run, the
                         config generated is automatically used to
                         run radeco rather than dumping it to a file.
";

fn spawn_shell(bname: String) -> i32 {
	radeco::spawn_shell(bname)
}

//fn radeco_pipe(args:&Args) -> i32 {
	//let mut r = Radeco::pipe().unwrap();
	//if args.flag_shell {
		//r.shell();
	//} else {
		//println!("Running radeco via pipe");
		//// TODO get offset, function, bin info, ..
	//}
	//r.close();
	//0
//}

fn write_file(fname: String, res: String) {
	let mut file = File::create(fname).unwrap();
	file.write_all(res.as_bytes()).unwrap();
}

fn json_builder(run: bool) {
	let inp = structs::input_builder();
	let mut runner = inp.validate().unwrap();
	if !run {
		let mut name = inp.name.clone().unwrap();
		let json = json::as_pretty_json(&inp);
		let raw_json = format!("{}", json);
		name.push_str(".json");
		write_file(name, raw_json);
	} else {
		runner.run();
		runner.dump();
	}
}

fn read_json(fname: String) -> structs::Input {
	let mut raw_json = String::new();
	let _ = File::open(fname).unwrap().read_to_string(&mut raw_json);
	json::decode(&*raw_json).unwrap()
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

	if args.flag_version {
		println!("Version: {:?}", VERSION);
		exit(0);
	}

	if args.flag_help {
		println!("{}", USAGE);
		exit(0);
	}

	//if args.arg_file != "" {
		//if args.arg_file == "-" {
			//exit(radeco_pipe(&args));
		//} else {
			//exit(radeco_file(&args));
		//}
	//}

	if args.flag_json_builder {
		json_builder(args.cmd_run);
	}

	if args.flag_from_json {
		if args.arg_file.is_none() {
			println!("{}", USAGE);
		}
		let inp = read_json(args.arg_file.clone().unwrap());
		let mut runner = inp.validate().unwrap();
		runner.run();
		runner.dump();
	}

	if args.flag_shell {
		if args.arg_file.is_none() {
			println!("{}", USAGE);
			exit(0);
		}
		let status = spawn_shell(args.arg_file.clone().unwrap());
		exit(status);
	}
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;

use core::str::FromStr;
use rust_decimal::Decimal;

macro_rules! bench_decimal_op {
    ($name:ident, $op:tt, $y:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            let x = Decimal::from_str("2.01").unwrap();
            let y = Decimal::from_str($y).unwrap();
            b.iter(|| {
                let result = x $op y;
                ::test::black_box(result);
            });
        }
    }
}

macro_rules! bench_fold_op {
    ($name:ident, $op:tt, $init:expr, $count:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            fn fold(values: &[Decimal]) -> Decimal {
                let mut acc: Decimal = $init.into();
                for value in values {
                    acc = acc $op value;
                }
                acc
            }

            let values: Vec<Decimal> = test::black_box((1..$count).map(|i| i.into()).collect());
            b.iter(|| {
                let result = fold(&values);
                ::test::black_box(result);
            });
        }
    }
}

/* Add */
bench_decimal_op!(add_one, +, "1");
bench_decimal_op!(add_two, +, "2");
bench_decimal_op!(add_one_hundred, +, "100");
bench_decimal_op!(add_point_zero_one, +, "0.01");
bench_decimal_op!(add_negative_point_five, +, "-0.5");
bench_decimal_op!(add_pi, +, "3.1415926535897932384626433832");
bench_decimal_op!(add_negative_pi, +, "-3.1415926535897932384626433832");

bench_fold_op!(add_10k, +, 0, 10_000);

/* Sub */
bench_decimal_op!(sub_one, -, "1");
bench_decimal_op!(sub_two, -, "2");
bench_decimal_op!(sub_one_hundred, -, "100");
bench_decimal_op!(sub_point_zero_one, -, "0.01");
bench_decimal_op!(sub_negative_point_five, -, "-0.5");
bench_decimal_op!(sub_pi, -, "3.1415926535897932384626433832");
bench_decimal_op!(sub_negative_pi, -, "-3.1415926535897932384626433832");

bench_fold_op!(sub_10k, -, 5_000_000, 10_000);

/* Mul */
bench_decimal_op!(mul_one, *, "1");
bench_decimal_op!(mul_two, *, "2");
bench_decimal_op!(mul_one_hundred, *, "100");
bench_decimal_op!(mul_point_zero_one, *, "0.01");
bench_decimal_op!(mul_negative_point_five, *, "-0.5");
bench_decimal_op!(mul_pi, *, "3.1415926535897932384626433832");
bench_decimal_op!(mul_negative_pi, *, "-3.1415926535897932384626433832");

/* Div */
bench_decimal_op!(div_one, /, "1");
bench_decimal_op!(div_two, /, "2");
bench_decimal_op!(div_one_hundred, /, "100");
bench_decimal_op!(div_point_zero_one, /, "0.01");
bench_decimal_op!(div_negative_point_five, /, "-0.5");
bench_decimal_op!(div_pi, /, "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "-3.1415926535897932384626433832");

bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);

/* Iteration */
struct DecimalIterator {
    count: usize,
}

impl DecimalIterator {
    fn new() -> DecimalIterator {
        DecimalIterator { count: 0 }
    }
}

impl Iterator for DecimalIterator {
    type Item = Decimal;

    fn next(&mut self) -> Option<Decimal> {
        self.count += 1;
        if self.count < 6 {
            Some(Decimal::new(314, 2))
        } else {
            None
        }
    }
}

#[bench]
fn iterator_individual(b: &mut ::test::Bencher) {
    b.iter(|| {
        let mut result = Decimal::new(0, 0);
        let iterator = DecimalIterator::new();
        for i in iterator {
            result += i;
        }
        ::test::black_box(result);
    });
}

#[bench]
fn iterator_sum(b: &mut ::test::Bencher) {
    b.iter(|| {
        let result: Decimal = DecimalIterator::new().sum();
        ::test::black_box(result);
    });
}

#[bench]
fn decimal_from_str(b: &mut test::Bencher) {
    let samples_strs = &[
        "3950.123456",
        "3950",
        "0.1",
        "0.01",
        "0.001",
        "0.0001",
        "0.00001",
        "0.000001",
        "1",
        "-100",
        "-123.456",
        "119996.25",
        "1000000",
        "9999999.99999",
        "12340.56789",
    ];

    b.iter(|| {
        for s in samples_strs {
            let result = Decimal::from_str(s).unwrap();
            test::black_box(result);
        }
    })
}

#[cfg(feature = "postgres")]
#[bench]
fn to_from_sql(b: &mut ::test::Bencher) {
    use postgres::types::{FromSql, Kind, ToSql, Type};

    let samples_strs = &[
        "3950.123456",
        "3950",
        "0.1",
        "0.01",
        "0.001",
        "0.0001",
        "0.00001",
        "0.000001",
        "1",
        "-100",
        "-123.456",
        "119996.25",
        "1000000",
        "9999999.99999",
        "12340.56789",
    ];

    let samples: Vec<Decimal> = test::black_box(samples_strs.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
    let t = Type::_new("".into(), 0, Kind::Simple, "".into());
    let mut vec = Vec::<u8>::with_capacity(100);

    b.iter(|| {
        for _ in 0..100 {
            for sample in &samples {
                vec.clear();
                sample.to_sql(&t, &mut vec).unwrap();
                let result = Decimal::from_sql(&t, &vec).unwrap();
                ::test::black_box(result);
            }
        }
    });
}
<commit_msg>Fix bench build<commit_after>#![feature(test)]

extern crate test;

use bytes::BytesMut;
use core::str::FromStr;
use rust_decimal::Decimal;

macro_rules! bench_decimal_op {
    ($name:ident, $op:tt, $y:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            let x = Decimal::from_str("2.01").unwrap();
            let y = Decimal::from_str($y).unwrap();
            b.iter(|| {
                let result = x $op y;
                ::test::black_box(result);
            });
        }
    }
}

macro_rules! bench_fold_op {
    ($name:ident, $op:tt, $init:expr, $count:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            fn fold(values: &[Decimal]) -> Decimal {
                let mut acc: Decimal = $init.into();
                for value in values {
                    acc = acc $op value;
                }
                acc
            }

            let values: Vec<Decimal> = test::black_box((1..$count).map(|i| i.into()).collect());
            b.iter(|| {
                let result = fold(&values);
                ::test::black_box(result);
            });
        }
    }
}

/* Add */
bench_decimal_op!(add_one, +, "1");
bench_decimal_op!(add_two, +, "2");
bench_decimal_op!(add_one_hundred, +, "100");
bench_decimal_op!(add_point_zero_one, +, "0.01");
bench_decimal_op!(add_negative_point_five, +, "-0.5");
bench_decimal_op!(add_pi, +, "3.1415926535897932384626433832");
bench_decimal_op!(add_negative_pi, +, "-3.1415926535897932384626433832");

bench_fold_op!(add_10k, +, 0, 10_000);

/* Sub */
bench_decimal_op!(sub_one, -, "1");
bench_decimal_op!(sub_two, -, "2");
bench_decimal_op!(sub_one_hundred, -, "100");
bench_decimal_op!(sub_point_zero_one, -, "0.01");
bench_decimal_op!(sub_negative_point_five, -, "-0.5");
bench_decimal_op!(sub_pi, -, "3.1415926535897932384626433832");
bench_decimal_op!(sub_negative_pi, -, "-3.1415926535897932384626433832");

bench_fold_op!(sub_10k, -, 5_000_000, 10_000);

/* Mul */
bench_decimal_op!(mul_one, *, "1");
bench_decimal_op!(mul_two, *, "2");
bench_decimal_op!(mul_one_hundred, *, "100");
bench_decimal_op!(mul_point_zero_one, *, "0.01");
bench_decimal_op!(mul_negative_point_five, *, "-0.5");
bench_decimal_op!(mul_pi, *, "3.1415926535897932384626433832");
bench_decimal_op!(mul_negative_pi, *, "-3.1415926535897932384626433832");

/* Div */
bench_decimal_op!(div_one, /, "1");
bench_decimal_op!(div_two, /, "2");
bench_decimal_op!(div_one_hundred, /, "100");
bench_decimal_op!(div_point_zero_one, /, "0.01");
bench_decimal_op!(div_negative_point_five, /, "-0.5");
bench_decimal_op!(div_pi, /, "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "-3.1415926535897932384626433832");

bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);

/* Iteration */
struct DecimalIterator {
    count: usize,
}

impl DecimalIterator {
    fn new() -> DecimalIterator {
        DecimalIterator { count: 0 }
    }
}

impl Iterator for DecimalIterator {
    type Item = Decimal;

    fn next(&mut self) -> Option<Decimal> {
        self.count += 1;
        if self.count < 6 {
            Some(Decimal::new(314, 2))
        } else {
            None
        }
    }
}

#[bench]
fn iterator_individual(b: &mut ::test::Bencher) {
    b.iter(|| {
        let mut result = Decimal::new(0, 0);
        let iterator = DecimalIterator::new();
        for i in iterator {
            result += i;
        }
        ::test::black_box(result);
    });
}

#[bench]
fn iterator_sum(b: &mut ::test::Bencher) {
    b.iter(|| {
        let result: Decimal = DecimalIterator::new().sum();
        ::test::black_box(result);
    });
}

#[bench]
fn decimal_from_str(b: &mut test::Bencher) {
    let samples_strs = &[
        "3950.123456",
        "3950",
        "0.1",
        "0.01",
        "0.001",
        "0.0001",
        "0.00001",
        "0.000001",
        "1",
        "-100",
        "-123.456",
        "119996.25",
        "1000000",
        "9999999.99999",
        "12340.56789",
    ];

    b.iter(|| {
        for s in samples_strs {
            let result = Decimal::from_str(s).unwrap();
            test::black_box(result);
        }
    })
}

#[cfg(feature = "postgres")]
#[bench]
fn to_from_sql(b: &mut ::test::Bencher) {
    use postgres::types::{FromSql, Kind, ToSql, Type};

    let samples_strs = &[
        "3950.123456",
        "3950",
        "0.1",
        "0.01",
        "0.001",
        "0.0001",
        "0.00001",
        "0.000001",
        "1",
        "-100",
        "-123.456",
        "119996.25",
        "1000000",
        "9999999.99999",
        "12340.56789",
    ];

    let samples: Vec<Decimal> = test::black_box(samples_strs.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
    let t = Type::new("".into(), 0, Kind::Simple, "".into());
    let mut bytes: BytesMut = BytesMut::with_capacity(100).into();

    b.iter(|| {
        for _ in 0..100 {
            for sample in &samples {
                bytes.clear();
                sample.to_sql(&t, &mut bytes).unwrap();
                let result = Decimal::from_sql(&t, &bytes).unwrap();
                ::test::black_box(result);
            }
        }
    });
}
<|endoftext|>


<commit_before><commit_msg>Convert doc comments to rustdoc<commit_after><|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufReader};
use std::path::PathBuf;

use cgmath::{Matrix4, Deg, Rad, Vector4, SquareMatrix, Vector3};
use soto::task::{task_log};
use soto::Error;
use sotolib_fbx::{RawFbx, id_name, friendly_name, ObjectTreeNode};
use sotolib_fbx::animation::{Animation};
use sotolib_fbx::simple::{SimpleFbx, ObjectType, ModelProperties, Geometry};
use sotolib_smd::{Smd, SmdVertex, SmdTriangle, SmdAnimationFrameBone, SmdBone};

pub fn create_reference_smd(fbx: &PathBuf) -> Result<Smd, Error> {
    // Read in the fbx we got told to convert
    let file = BufReader::new(File::open(&fbx).unwrap());
    let fbx = SimpleFbx::from_raw(&RawFbx::parse(file).unwrap()).unwrap();
    let fbx_tree = ObjectTreeNode::from_simple(&fbx);

    // Go over all FBX root nodes and turn them into SMD data
    let mut smd = Smd::new();
    process_fbx_node(
        &fbx_tree, &mut smd,
        &Matrix4::identity(), Vector3::new(0.0, 0.0, 0.0), &Matrix4::identity(),
        None
    )?;

    Ok(smd)
}

pub fn create_animation_smd(_ref_smd: &Smd, fbx: &PathBuf) -> Result<Smd, Error> {
    // Read in the fbx we got told to convert
    let file = BufReader::new(File::open(&fbx).unwrap());
    let mut fbx = SimpleFbx::from_raw(&RawFbx::parse(file).unwrap()).unwrap();

    // Read in the animation data itself
    let animation = Animation::from_simple(&fbx).unwrap();

    // Finally, turn the animation data into bone positions in the SMD
    let smd = Smd::new();
    for frame in 0..animation.frame_count(&fbx) {
        // First transform the FBX for this frame
        animation.transform_fbx_to_frame(&mut fbx, frame);

        // Now go over all models
        /*for model in fbx.models() {
            // For this model, look up the matching BoneId in the reference SMD
            if let Some(bone) = ref_smd.id_of_bone(&id_name(&model.name)) {
                // Now add an entry in the animation SMD for that bone at this frame
                // TODO
            }
        }*/
    }

    Ok(smd)
}

fn process_fbx_node(
    fbx_node: &ObjectTreeNode, mut smd: &mut Smd,
    matrix: &Matrix4<f32>, pivot: Vector3<f32>, parent_scale_inverse: &Matrix4<f32>,
    current_bone: Option<&SmdBone>,
) -> Result<(), Error> {
    // Perform node type specific information
    match fbx_node.object.class {
        ObjectType::Geometry(ref geometry) =>
            process_geometry(smd, geometry, matrix, current_bone.unwrap()),
        ObjectType::Model(ref _model) =>
            process_model(fbx_node, smd, matrix, pivot, parent_scale_inverse, current_bone)?,
        _ => {
            // Just go straight to the children
            for node in &fbx_node.nodes {
                process_fbx_node(node, smd, matrix, pivot, parent_scale_inverse, current_bone)?;
            }
        }
    }

    Ok(())
}

fn process_geometry(smd: &mut Smd, geometry: &Geometry, matrix: &Matrix4<f32>, current_bone: &SmdBone) {
    // Add triangles to parent node
    let tris = geometry.triangles();
    for tri in tris {
        // Turn the vertices in this triangle to SMD vertices
        let mut smd_verts: [SmdVertex; 3] = Default::default();
        for (i, vert) in tri.iter().enumerate() {
            // Multiply the vectors that need to be multiplied
            let pos = matrix * Vector4::new(vert.0[0], vert.0[1], vert.0[2], 1.0);
            let norm = matrix * Vector4::new(vert.1[0], vert.1[1], vert.1[2], 0.0);

            smd_verts[i] = SmdVertex {
                parent_bone: current_bone.id, // This is overwritten by links
                position: pos.truncate().into(),
                normal: norm.truncate().into(),
                uv: vert.2,
                links: vec!(
                    /*Not needed, we aren't using weights anyways so this done by parent_bone
                    SmdLink {
                        bone: bone_id,
                        weight: 1.0,
                    }*/
                )
            };
        }

        // Add the actual SMD triangle
        smd.triangles.push(SmdTriangle {
            material: "layl_test_texture".into(),
            vertices: smd_verts,
        });
    }
}

fn process_model(
    fbx_node: &ObjectTreeNode, smd: &mut Smd,
    matrix: &Matrix4<f32>, pivot: Vector3<f32>, parent_scale_inverse: &Matrix4<f32>,
    current_bone: Option<&SmdBone>
) -> Result<(), Error> {
    task_log(format!("Adding model \"{}\" to SMD data", friendly_name(&fbx_node.object.name)));
    let properties = ModelProperties::from_generic(&fbx_node.object.properties);

    // Create a new transformation matrix
    let (vertices_matrix, rot_pivot, scale_inverse) = local_matrices(&properties, parent_scale_inverse);

    // Create a new bone and set the transformations
    let new_bone = smd.new_bone(
        &id_name(&fbx_node.object.name).unwrap(),
        current_bone.map(|b| b.id)
    )
        .ok_or_else(|| Error::Task(format!(
            "Bone \"{}\" exists multiple times in the FBX",
            &fbx_node.object.name
        )))?
        .clone(); // Clone needed to avoid a borrow since we need to mut borrow SMD later
    let first_frame = SmdAnimationFrameBone {
        // This needs to be derived from the matrix to get the right location
        translation: (
            Matrix4::from_translation(-pivot) *
            vertices_matrix *
            Vector4::new(rot_pivot.x, rot_pivot.y, rot_pivot.z, 1.0)
        ).truncate().into(),
        // This can just be directly copied over
        rotation: [
            Rad::from(Deg(properties.rotation[0])).0,
            Rad::from(Deg(properties.rotation[1])).0,
            Rad::from(Deg(properties.rotation[2])).0,
        ],
    };
    smd.set_animation(0, new_bone.id, first_frame);

    // Make new matrices for children
    let matrix = matrix * vertices_matrix;
    let pivot = rot_pivot;
    let parent_scale_inverse = scale_inverse;

    // Make sure the child nodes will receive this new bone
    for node in &fbx_node.nodes {
        process_fbx_node(node, smd, &matrix, pivot, &parent_scale_inverse, Some(&new_bone))?;
    }

    Ok(())
}

/// Returns (vertices_matrix, rot_pivot, scale_inverse)
fn local_matrices(
    properties: &ModelProperties, parent_scale_inverse: &Matrix4<f32>
) -> (Matrix4<f32>, Vector3<f32>, Matrix4<f32>) {
    let rotation_offset = properties.rotation_offset.into();
    let rotation_offset_mat = Matrix4::from_translation(rotation_offset);
    let rot_pivot: Vector3<_> = properties.rotation_pivot.into();
    let rot_pivot_mat = Matrix4::from_translation(rot_pivot);

    let pre_rotation = euler_rotation_to_matrix(properties.pre_rotation);
    let rotation = euler_rotation_to_matrix(properties.rotation);
    let post_rotation = euler_rotation_to_matrix(properties.post_rotation);

    let scale = Matrix4::from_nonuniform_scale(
        properties.scale[0],
        properties.scale[1],
        properties.scale[2]
    );

    let local_matrix_for_vertices =
        Matrix4::from_translation(properties.translation.into()) *
        parent_scale_inverse * // I'm not 100% on this, try removing if scale messes up

        // Rotation
        rotation_offset_mat *
        rot_pivot_mat *
        pre_rotation *
        rotation *
        post_rotation *
        rot_pivot_mat.invert().unwrap() *

        // Scale
        //scale_offset *
        //scale_pivot *
        scale; // *
        //scale_pivot.invert().unwrap();

    (local_matrix_for_vertices, rot_pivot, scale.invert().unwrap())
}

fn euler_rotation_to_matrix(rot_degs: [f32; 3]) -> Matrix4<f32> {
    Matrix4::from_angle_z(Deg(rot_degs[2])) *
    Matrix4::from_angle_y(Deg(rot_degs[1])) *
    Matrix4::from_angle_x(Deg(rot_degs[0]))
}
<commit_msg>Fix scaling bug caused by confusion<commit_after>use std::fs::File;
use std::io::{BufReader};
use std::path::PathBuf;

use cgmath::{Matrix4, Deg, Rad, Vector4, SquareMatrix, Vector3};
use soto::task::{task_log};
use soto::Error;
use sotolib_fbx::{RawFbx, id_name, friendly_name, ObjectTreeNode};
use sotolib_fbx::animation::{Animation};
use sotolib_fbx::simple::{SimpleFbx, ObjectType, ModelProperties, Geometry};
use sotolib_smd::{Smd, SmdVertex, SmdTriangle, SmdAnimationFrameBone, SmdBone};

pub fn create_reference_smd(fbx: &PathBuf) -> Result<Smd, Error> {
    // Read in the fbx we got told to convert
    let file = BufReader::new(File::open(&fbx).unwrap());
    let fbx = SimpleFbx::from_raw(&RawFbx::parse(file).unwrap()).unwrap();
    let fbx_tree = ObjectTreeNode::from_simple(&fbx);

    // Go over all FBX root nodes and turn them into SMD data
    let mut smd = Smd::new();
    process_fbx_node(
        &fbx_tree, &mut smd,
        &Matrix4::identity(), Vector3::new(0.0, 0.0, 0.0),
        None
    )?;

    Ok(smd)
}

pub fn create_animation_smd(_ref_smd: &Smd, fbx: &PathBuf) -> Result<Smd, Error> {
    // Read in the fbx we got told to convert
    let file = BufReader::new(File::open(&fbx).unwrap());
    let mut fbx = SimpleFbx::from_raw(&RawFbx::parse(file).unwrap()).unwrap();

    // Read in the animation data itself
    let animation = Animation::from_simple(&fbx).unwrap();

    // Finally, turn the animation data into bone positions in the SMD
    let smd = Smd::new();
    for frame in 0..animation.frame_count(&fbx) {
        // First transform the FBX for this frame
        animation.transform_fbx_to_frame(&mut fbx, frame);

        // Now go over all models
        /*for model in fbx.models() {
            // For this model, look up the matching BoneId in the reference SMD
            if let Some(bone) = ref_smd.id_of_bone(&id_name(&model.name)) {
                // Now add an entry in the animation SMD for that bone at this frame
                // TODO
            }
        }*/
    }

    Ok(smd)
}

fn process_fbx_node(
    fbx_node: &ObjectTreeNode, mut smd: &mut Smd,
    matrix: &Matrix4<f32>, pivot: Vector3<f32>,
    current_bone: Option<&SmdBone>,
) -> Result<(), Error> {
    // Perform node type specific information
    match fbx_node.object.class {
        ObjectType::Geometry(ref geometry) =>
            process_geometry(smd, geometry, matrix, current_bone.unwrap()),
        ObjectType::Model(ref _model) =>
            process_model(fbx_node, smd, matrix, pivot, current_bone)?,
        _ => {
            // Just go straight to the children
            for node in &fbx_node.nodes {
                process_fbx_node(node, smd, matrix, pivot, current_bone)?;
            }
        }
    }

    Ok(())
}

fn process_geometry(smd: &mut Smd, geometry: &Geometry, matrix: &Matrix4<f32>, current_bone: &SmdBone) {
    // Add triangles to parent node
    let tris = geometry.triangles();
    for tri in tris {
        // Turn the vertices in this triangle to SMD vertices
        let mut smd_verts: [SmdVertex; 3] = Default::default();
        for (i, vert) in tri.iter().enumerate() {
            // Multiply the vectors that need to be multiplied
            let pos = matrix * Vector4::new(vert.0[0], vert.0[1], vert.0[2], 1.0);
            let norm = matrix * Vector4::new(vert.1[0], vert.1[1], vert.1[2], 0.0);

            smd_verts[i] = SmdVertex {
                parent_bone: current_bone.id, // This is overwritten by links
                position: pos.truncate().into(),
                normal: norm.truncate().into(),
                uv: vert.2,
                links: vec!(
                    /*Not needed, we aren't using weights anyways so this done by parent_bone
                    SmdLink {
                        bone: bone_id,
                        weight: 1.0,
                    }*/
                )
            };
        }

        // Add the actual SMD triangle
        smd.triangles.push(SmdTriangle {
            material: "layl_test_texture".into(),
            vertices: smd_verts,
        });
    }
}

fn process_model(
    fbx_node: &ObjectTreeNode, smd: &mut Smd,
    matrix: &Matrix4<f32>, pivot: Vector3<f32>,
    current_bone: Option<&SmdBone>
) -> Result<(), Error> {
    task_log(format!("Adding model \"{}\" to SMD data", friendly_name(&fbx_node.object.name)));
    let properties = ModelProperties::from_generic(&fbx_node.object.properties);

    // Create a new transformation matrix
    let (vertices_matrix, rot_pivot) = local_matrices(&properties);

    // Create a new bone and set the transformations
    let new_bone = smd.new_bone(
        &id_name(&fbx_node.object.name).unwrap(),
        current_bone.map(|b| b.id)
    )
        .ok_or_else(|| Error::Task(format!(
            "Bone \"{}\" exists multiple times in the FBX",
            &fbx_node.object.name
        )))?
        .clone(); // Clone needed to avoid a borrow since we need to mut borrow SMD later
    let first_frame = SmdAnimationFrameBone {
        // This needs to be derived from the matrix to get the right location
        translation: (
            Matrix4::from_translation(-pivot) *
            vertices_matrix *
            Vector4::new(rot_pivot.x, rot_pivot.y, rot_pivot.z, 1.0)
        ).truncate().into(),
        // This can just be directly copied over
        rotation: [
            Rad::from(Deg(properties.rotation[0])).0,
            Rad::from(Deg(properties.rotation[1])).0,
            Rad::from(Deg(properties.rotation[2])).0,
        ],
    };
    smd.set_animation(0, new_bone.id, first_frame);

    // Make new matrices for children
    let matrix = matrix * vertices_matrix;
    let pivot = rot_pivot;

    // Make sure the child nodes will receive this new bone
    for node in &fbx_node.nodes {
        process_fbx_node(node, smd, &matrix, pivot, Some(&new_bone))?;
    }

    Ok(())
}

/// Returns (vertices_matrix, rot_pivot)
fn local_matrices(properties: &ModelProperties) -> (Matrix4<f32>, Vector3<f32>) {
    let rotation_offset = properties.rotation_offset.into();
    let rotation_offset_mat = Matrix4::from_translation(rotation_offset);
    let rot_pivot: Vector3<_> = properties.rotation_pivot.into();
    let rot_pivot_mat = Matrix4::from_translation(rot_pivot);

    let pre_rotation = euler_rotation_to_matrix(properties.pre_rotation);
    let rotation = euler_rotation_to_matrix(properties.rotation);
    let post_rotation = euler_rotation_to_matrix(properties.post_rotation);

    let scale = Matrix4::from_nonuniform_scale(
        properties.scale[0],
        properties.scale[1],
        properties.scale[2]
    );

    let local_matrix_for_vertices =
        Matrix4::from_translation(properties.translation.into()) *

        // Rotation
        rotation_offset_mat *
        rot_pivot_mat *
        pre_rotation *
        rotation *
        post_rotation *
        rot_pivot_mat.invert().unwrap() *

        // Scale TODO: Complete implementation
        //scale_offset *
        //scale_pivot *
        scale; // *
        //scale_pivot.invert().unwrap();

    (local_matrix_for_vertices, rot_pivot)
}

fn euler_rotation_to_matrix(rot_degs: [f32; 3]) -> Matrix4<f32> {
    Matrix4::from_angle_z(Deg(rot_degs[2])) *
    Matrix4::from_angle_y(Deg(rot_degs[1])) *
    Matrix4::from_angle_x(Deg(rot_degs[0]))
}
<|endoftext|>