<commit_before>use std::collections::HashSet;
use std::sync::Arc;

use dora_parser::ast;
use dora_parser::ast::TypeParam;

use crate::error::msg::SemError;
use crate::semck::{read_type, AllowSelf, TypeParamContext};
use crate::sym::{NestedSymTable, Sym};
use crate::ty::SourceType;
use crate::vm::{EnumData, EnumVariant, FileId, TypeParamId, VM};

pub fn check(vm: &VM) {
    for xenum in &vm.enums {
        let mut xenum = xenum.write();
        let ast = xenum.ast.clone();

        let mut enumck = EnumCheck {
            vm,
            file_id: xenum.file_id,
            ast: &ast,
            xenum: &mut *xenum,
        };

        enumck.check();
    }
}

struct EnumCheck<'x> {
    vm: &'x VM,
    file_id: FileId,
    ast: &'x Arc<ast::Enum>,
    xenum: &'x mut EnumData,
}

impl<'x> EnumCheck<'x> {
    fn check(&mut self) {
        let mut symtable = NestedSymTable::new(self.vm, self.xenum.namespace_id);

        symtable.push_level();

        if let Some(ref type_params) = self.ast.type_params {
            self.check_type_params(type_params, &mut symtable);
        }

        let mut variant_id: usize = 0;
        let mut simple_enumeration = true;

        for value in &self.ast.variants {
            let mut types: Vec<SourceType> = Vec::new();

            if let Some(ref variant_types) = value.types {
                for ty in variant_types {
                    let variant_ty = read_type(
                        self.vm,
                        &symtable,
                        self.file_id.into(),
                        ty,
                        TypeParamContext::Enum(self.xenum.id),
                        AllowSelf::No,
                    )
                    .unwrap_or(SourceType::Error);
                    types.push(variant_ty);
                }
            }

            if types.len() > 0 {
                simple_enumeration = false;
            }

            self.xenum.variants[variant_id].types = types;
            variant_id += 1;
        }

        self.xenum.simple_enumeration = simple_enumeration;

        symtable.pop_level();
    }

    fn check_type_params(&mut self, type_params: &[TypeParam], symtable: &mut NestedSymTable) {
        if type_params.len() > 0 {
            let mut names = HashSet::new();
            let mut type_param_id = 0;
            let mut params = Vec::new();

            for type_param in type_params {
                if !names.insert(type_param.name) {
                    let name = self.vm.interner.str(type_param.name).to_string();
                    let msg = SemError::TypeParamNameNotUnique(name);
                    self.vm
                        .diag
                        .lock()
                        .report(self.file_id, type_param.pos, msg);
                }

                params.push(SourceType::TypeParam(TypeParamId(type_param_id)));

                for bound in &type_param.bounds {
                    let ty = read_type(
                        self.vm,
                        symtable,
                        self.file_id,
                        bound,
                        TypeParamContext::Enum(self.xenum.id),
                        AllowSelf::No,
                    );

                    match ty {
                        Some(SourceType::Trait(trait_id, _)) => {
                            if !self.xenum.type_params[type_param_id]
                                .trait_bounds
                                .insert(trait_id)
                            {
                                let msg = SemError::DuplicateTraitBound;
                                self.vm
                                    .diag
                                    .lock()
                                    .report(self.file_id, type_param.pos, msg);
                            }
                        }

                        None => {
                            // unknown type, error is already thrown
                        }

                        _ => {
                            let msg = SemError::BoundExpected;
                            self.vm.diag.lock().report(self.file_id, bound.pos(), msg);
                        }
                    }
                }

                let sym = Sym::TypeParam(TypeParamId(type_param_id));
                symtable.insert(type_param.name, sym);
                type_param_id += 1;
            }
        } else {
            let msg = SemError::TypeParamsExpected;
            self.vm.diag.lock().report(self.file_id, self.ast.pos, msg);
        }
    }
}

pub fn check_variants(vm: &VM) {
    for xenum in &vm.enums {
        let mut xenum = xenum.write();
        let ast = xenum.ast.clone();

        let mut enumck = EnumCheckVariants {
            vm,
            file_id: xenum.file_id,
            ast: &ast,
            xenum: &mut *xenum,
        };

        enumck.check();
    }
}

struct EnumCheckVariants<'x> {
    vm: &'x VM,
    file_id: FileId,
    ast: &'x Arc<ast::Enum>,
    xenum: &'x mut EnumData,
}

impl<'x> EnumCheckVariants<'x> {
    fn check(&mut self) {
        let mut next_variant_id: u32 = 0;

        for value in &self.ast.variants {
            let variant = EnumVariant {
                id: next_variant_id as usize,
                name: value.name,
                types: Vec::new(),
            };
            self.xenum.variants.push(variant);
            let result = self.xenum.name_to_value.insert(value.name, next_variant_id);

            if result.is_some() {
                let name = self.vm.interner.str(value.name).to_string();
                self.vm.diag.lock().report(
                    self.xenum.file_id,
                    value.pos,
                    SemError::ShadowEnumValue(name),
                );
            }

            next_variant_id += 1;
        }

        if self.ast.variants.is_empty() {
            self.vm
                .diag
                .lock()
                .report(self.xenum.file_id, self.ast.pos, SemError::NoEnumValue);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::error::msg::SemError;
    use crate::semck::tests::*;

    #[test]
    fn enum_definitions() {
        err("enum Foo {}", pos(1, 1), SemError::NoEnumValue);
        ok("enum Foo { A, B, C }");
        err(
            "enum Foo { A, A }",
            pos(1, 15),
            SemError::ShadowEnumValue("A".into()),
        );
    }

    #[test]
    fn enum_with_argument() {
        ok("
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_a(): Foo { Foo::A(1) }
            fun give_me_b(): Foo { Foo::B(2.0F) }
            fun give_me_c(): Foo { Foo::C }

        ");
    }

    #[test]
    fn enum_wrong_type() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_a(): Foo { Foo::A(2.0F) }

        ",
            pos(3, 42),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["Int32".into()],
                vec!["Float32".into()],
            ),
        );
    }

    #[test]
    fn enum_missing_args() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_a(): Foo { Foo::A }

        ",
            pos(3, 39),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["Int32".into()],
                Vec::new(),
            ),
        );
    }

    #[test]
    fn enum_unexpected_args() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_c(): Foo { Foo::C(12.0F) }

        ",
            pos(3, 42),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "C".into(),
                Vec::new(),
                vec!["Float32".into()],
            ),
        );
    }

    #[test]
    fn enum_parens_but_no_args() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_c(): Foo { Foo::C() }
        ",
            pos(3, 42),
            SemError::EnumArgsNoParens("Foo".into(), "C".into()),
        );
    }

    #[test]
    fn enum_copy() {
        ok("
            enum Foo { A(Int32), B(Float32), C}
            fun foo_test(y: Foo): Foo { let x: Foo = y; x }
        ");
    }

    #[test]
    fn enum_generic() {
        ok("
            enum Foo[T] { One(T), Two }
        ");
    }

    #[test]
    fn enum_with_type_param() {
        ok("trait SomeTrait {} enum MyOption[T: SomeTrait] { None, Some(T) }");
    }

    #[test]
    fn enum_generic_with_failures() {
        err(
            "enum MyOption[] { A, B }",
            pos(1, 1),
            SemError::TypeParamsExpected,
        );

        err(
            "enum MyOption[X, X] { A, B }",
            pos(1, 18),
            SemError::TypeParamNameNotUnique("X".into()),
        );

        err(
            "enum MyOption[X: NonExistingTrait] { A, B }",
            pos(1, 18),
            SemError::UnknownIdentifier("NonExistingTrait".into()),
        );
    }

    #[test]
    fn check_enum_type() {
        err(
            "
                enum MyOption[X] { A, B }
                fun foo(v: MyOption) {}
            ",
            pos(3, 28),
            SemError::WrongNumberTypeParams(1, 0),
        );
    }

    #[test]
    fn check_enum_value() {
        ok("
            enum Foo { A(Int32), B }
            fun foo(): Foo { Foo::A(1) }
            fun bar(): Foo { Foo::B }
        ");

        err(
            "
            enum Foo { A(Int32), B }
            fun foo(): Foo { Foo::A(true) }
        ",
            pos(3, 36),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["Int32".into()],
                vec!["Bool".into()],
            ),
        );
    }

    #[test]
    fn check_enum_value_generic() {
        ok("
            enum Foo[T] { A, B }
            fun foo() { let tmp = Foo[String]::B; }
        ");

        err(
            "
            trait SomeTrait {}
            enum Foo[T: SomeTrait] { A, B }
            fun foo() { let tmp = Foo[String]::B; }
        ",
            pos(4, 46),
            SemError::TypeNotImplementingTrait("String".into(), "SomeTrait".into()),
        );
    }

    #[test]
    fn enum_with_generic_argument() {
        ok("
            enum Foo[T] { A(T), B }
            fun foo() { let tmp = Foo[Int32]::A(0); }
        ");

        err(
            "
            enum Foo[T] { A(T), B }
            fun foo() { let tmp = Foo[Int32]::A(true); }
        ",
            pos(3, 48),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["T".into()],
                vec!["Bool".into()],
            ),
        );
    }

    #[test]
    fn enum_move_generic() {
        ok("
            enum Foo[T] { A(T), B }
            fun foo(x: Foo[Int32]): Foo[Int32] { x }
        ");

        err(
            "
            enum Foo[T] { A(T), B }
            fun foo(x: Foo[Int32]): Foo[Float32] { x }
        ",
            pos(3, 50),
            SemError::ReturnType("Foo[Float32]".into(), "Foo[Int32]".into()),
        );
    }
}
<commit_msg>fix timeout when using enum in its own definition<commit_after>use std::collections::HashSet;
use std::sync::Arc;

use parking_lot::RwLock;

use dora_parser::ast;
use dora_parser::ast::TypeParam;

use crate::error::msg::SemError;
use crate::semck::{read_type, AllowSelf, TypeParamContext};
use crate::sym::{NestedSymTable, Sym};
use crate::ty::SourceType;
use crate::vm::{EnumData, EnumVariant, FileId, TypeParamId, VM};

pub fn check(vm: &VM) {
    for xenum in &vm.enums {
        let ast = xenum.read().ast.clone();

        let mut enumck = EnumCheck {
            vm,
            file_id: xenum.read().file_id,
            ast: &ast,
            xenum,
        };

        enumck.check();
    }
}

struct EnumCheck<'x> {
    vm: &'x VM,
    file_id: FileId,
    ast: &'x Arc<ast::Enum>,
    xenum: &'x RwLock<EnumData>,
}

impl<'x> EnumCheck<'x> {
    fn check(&mut self) {
        let mut symtable = NestedSymTable::new(self.vm, self.xenum.read().namespace_id);

        symtable.push_level();

        if let Some(ref type_params) = self.ast.type_params {
            self.check_type_params(type_params, &mut symtable);
        }

        let mut variant_id: usize = 0;
        let mut simple_enumeration = true;

        for value in &self.ast.variants {
            let mut types: Vec<SourceType> = Vec::new();

            if let Some(ref variant_types) = value.types {
                for ty in variant_types {
                    let variant_ty = read_type(
                        self.vm,
                        &symtable,
                        self.file_id.into(),
                        ty,
                        TypeParamContext::Enum(self.xenum.read().id),
                        AllowSelf::No,
                    )
                    .unwrap_or(SourceType::Error);
                    types.push(variant_ty);
                }
            }

            if types.len() > 0 {
                simple_enumeration = false;
            }

            self.xenum.write().variants[variant_id].types = types;
            variant_id += 1;
        }

        self.xenum.write().simple_enumeration = simple_enumeration;

        symtable.pop_level();
    }

    fn check_type_params(&mut self, type_params: &[TypeParam], symtable: &mut NestedSymTable) {
        if type_params.len() > 0 {
            let mut names = HashSet::new();
            let mut type_param_id = 0;
            let mut params = Vec::new();

            for type_param in type_params {
                if !names.insert(type_param.name) {
                    let name = self.vm.interner.str(type_param.name).to_string();
                    let msg = SemError::TypeParamNameNotUnique(name);
                    self.vm
                        .diag
                        .lock()
                        .report(self.file_id, type_param.pos, msg);
                }

                params.push(SourceType::TypeParam(TypeParamId(type_param_id)));

                for bound in &type_param.bounds {
                    let ty = read_type(
                        self.vm,
                        symtable,
                        self.file_id,
                        bound,
                        TypeParamContext::Enum(self.xenum.read().id),
                        AllowSelf::No,
                    );

                    match ty {
                        Some(SourceType::Trait(trait_id, _)) => {
                            if !self.xenum.write().type_params[type_param_id]
                                .trait_bounds
                                .insert(trait_id)
                            {
                                let msg = SemError::DuplicateTraitBound;
                                self.vm
                                    .diag
                                    .lock()
                                    .report(self.file_id, type_param.pos, msg);
                            }
                        }

                        None => {
                            // unknown type, error is already thrown
                        }

                        _ => {
                            let msg = SemError::BoundExpected;
                            self.vm.diag.lock().report(self.file_id, bound.pos(), msg);
                        }
                    }
                }

                let sym = Sym::TypeParam(TypeParamId(type_param_id));
                symtable.insert(type_param.name, sym);
                type_param_id += 1;
            }
        } else {
            let msg = SemError::TypeParamsExpected;
            self.vm.diag.lock().report(self.file_id, self.ast.pos, msg);
        }
    }
}

pub fn check_variants(vm: &VM) {
    for xenum in &vm.enums {
        let mut xenum = xenum.write();
        let ast = xenum.ast.clone();

        let mut enumck = EnumCheckVariants {
            vm,
            file_id: xenum.file_id,
            ast: &ast,
            xenum: &mut *xenum,
        };

        enumck.check();
    }
}

struct EnumCheckVariants<'x> {
    vm: &'x VM,
    file_id: FileId,
    ast: &'x Arc<ast::Enum>,
    xenum: &'x mut EnumData,
}

impl<'x> EnumCheckVariants<'x> {
    fn check(&mut self) {
        let mut next_variant_id: u32 = 0;

        for value in &self.ast.variants {
            let variant = EnumVariant {
                id: next_variant_id as usize,
                name: value.name,
                types: Vec::new(),
            };

            self.xenum.variants.push(variant);
            let result = self.xenum.name_to_value.insert(value.name, next_variant_id);

            if result.is_some() {
                let name = self.vm.interner.str(value.name).to_string();
                self.vm.diag.lock().report(
                    self.xenum.file_id,
                    value.pos,
                    SemError::ShadowEnumValue(name),
                );
            }

            next_variant_id += 1;
        }

        if self.ast.variants.is_empty() {
            self.vm
                .diag
                .lock()
                .report(self.xenum.file_id, self.ast.pos, SemError::NoEnumValue);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::error::msg::SemError;
    use crate::semck::tests::*;

    #[test]
    fn enum_definitions() {
        err("enum Foo {}", pos(1, 1), SemError::NoEnumValue);
        ok("enum Foo { A, B, C }");
        err(
            "enum Foo { A, A }",
            pos(1, 15),
            SemError::ShadowEnumValue("A".into()),
        );
    }

    #[test]
    fn enum_with_argument() {
        ok("
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_a(): Foo { Foo::A(1) }
            fun give_me_b(): Foo { Foo::B(2.0F) }
            fun give_me_c(): Foo { Foo::C }

        ");
    }

    #[test]
    fn enum_wrong_type() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_a(): Foo { Foo::A(2.0F) }

        ",
            pos(3, 42),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["Int32".into()],
                vec!["Float32".into()],
            ),
        );
    }

    #[test]
    fn enum_missing_args() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_a(): Foo { Foo::A }

        ",
            pos(3, 39),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["Int32".into()],
                Vec::new(),
            ),
        );
    }

    #[test]
    fn enum_unexpected_args() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_c(): Foo { Foo::C(12.0F) }

        ",
            pos(3, 42),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "C".into(),
                Vec::new(),
                vec!["Float32".into()],
            ),
        );
    }

    #[test]
    fn enum_parens_but_no_args() {
        err(
            "
            enum Foo { A(Int32), B(Float32), C}
            fun give_me_c(): Foo { Foo::C() }
        ",
            pos(3, 42),
            SemError::EnumArgsNoParens("Foo".into(), "C".into()),
        );
    }

    #[test]
    fn enum_copy() {
        ok("
            enum Foo { A(Int32), B(Float32), C}
            fun foo_test(y: Foo): Foo { let x: Foo = y; x }
        ");
    }

    #[test]
    fn enum_generic() {
        ok("
            enum Foo[T] { One(T), Two }
        ");
    }

    #[test]
    fn enum_with_type_param() {
        ok("trait SomeTrait {} enum MyOption[T: SomeTrait] { None, Some(T) }");
    }

    #[test]
    fn enum_generic_with_failures() {
        err(
            "enum MyOption[] { A, B }",
            pos(1, 1),
            SemError::TypeParamsExpected,
        );

        err(
            "enum MyOption[X, X] { A, B }",
            pos(1, 18),
            SemError::TypeParamNameNotUnique("X".into()),
        );

        err(
            "enum MyOption[X: NonExistingTrait] { A, B }",
            pos(1, 18),
            SemError::UnknownIdentifier("NonExistingTrait".into()),
        );
    }

    #[test]
    fn check_enum_type() {
        err(
            "
                enum MyOption[X] { A, B }
                fun foo(v: MyOption) {}
            ",
            pos(3, 28),
            SemError::WrongNumberTypeParams(1, 0),
        );
    }

    #[test]
    fn check_enum_value() {
        ok("
            enum Foo { A(Int32), B }
            fun foo(): Foo { Foo::A(1) }
            fun bar(): Foo { Foo::B }
        ");

        err(
            "
            enum Foo { A(Int32), B }
            fun foo(): Foo { Foo::A(true) }
        ",
            pos(3, 36),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["Int32".into()],
                vec!["Bool".into()],
            ),
        );
    }

    #[test]
    fn check_enum_value_generic() {
        ok("
            enum Foo[T] { A, B }
            fun foo() { let tmp = Foo[String]::B; }
        ");

        err(
            "
            trait SomeTrait {}
            enum Foo[T: SomeTrait] { A, B }
            fun foo() { let tmp = Foo[String]::B; }
        ",
            pos(4, 46),
            SemError::TypeNotImplementingTrait("String".into(), "SomeTrait".into()),
        );
    }

    #[test]
    fn enum_with_generic_argument() {
        ok("
            enum Foo[T] { A(T), B }
            fun foo() { let tmp = Foo[Int32]::A(0); }
        ");

        err(
            "
            enum Foo[T] { A(T), B }
            fun foo() { let tmp = Foo[Int32]::A(true); }
        ",
            pos(3, 48),
            SemError::EnumArgsIncompatible(
                "Foo".into(),
                "A".into(),
                vec!["T".into()],
                vec!["Bool".into()],
            ),
        );
    }

    #[test]
    fn enum_move_generic() {
        ok("
            enum Foo[T] { A(T), B }
            fun foo(x: Foo[Int32]): Foo[Int32] { x }
        ");

        err(
            "
            enum Foo[T] { A(T), B }
            fun foo(x: Foo[Int32]): Foo[Float32] { x }
        ",
            pos(3, 50),
            SemError::ReturnType("Foo[Float32]".into(), "Foo[Int32]".into()),
        );
    }

    #[test]
    fn enum_nested() {
        ok("
            enum Foo { A(Foo), B }
        ");
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_int, size_t, strncpy};
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;

mod add;
pub use add::add;

mod borrow;
pub use borrow::borrow;

mod cmp;
pub use cmp::cmp;

mod denormalize;
pub use denormalize::denormalize;

mod normalize;
pub use normalize::normalize;

mod sub;
pub use sub::sub;

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) -> c_int {
    unsafe {
        match add(CStr::from_ptr(num_l).to_str().unwrap(), CStr::from_ptr(num_r).to_str().unwrap()) {
            Ok(sum) => {
                if sum.len() > (dstlen - 1) {
                    1
                } else {
                    let csum = CString::new(sum).unwrap();
                    strncpy(dst, csum.as_ptr() as *const i8, dstlen);
                    0
                }
            },
            Err(_) => {
                1
            }
        }
    }
}

#[no_mangle]
pub extern fn rnc_sub(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) -> c_int {
    unsafe {
        match sub(CStr::from_ptr(num_l).to_str().unwrap(), CStr::from_ptr(num_r).to_str().unwrap()) {
            Ok(difference) => {
                //if sum.len() > (dstlen - 1) {
                //1
                //} else {
                let cdiff = CString::new(difference).unwrap();
                strncpy(dst, cdiff.as_ptr() as *const i8, dstlen);
                0
            },
            Err(_) => {
                1
            }
        }
    }
}
<commit_msg>Minimize unsafe blocks in rnc_add<commit_after>extern crate libc;

use libc::{c_int, size_t, strncpy};
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;

mod add;
pub use add::add;

mod borrow;
pub use borrow::borrow;

mod cmp;
pub use cmp::cmp;

mod denormalize;
pub use denormalize::denormalize;

mod normalize;
pub use normalize::normalize;

mod sub;
pub use sub::sub;

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, raw_l: *const c_char, raw_r: *const c_char) -> c_int {
    let num_l;
    let num_r;

    unsafe {
        num_l = CStr::from_ptr(raw_l).to_str().unwrap();
        num_r = CStr::from_ptr(raw_r).to_str().unwrap();
    }

    match add(num_l, num_r) {
        Ok(sum) => {
            if sum.len() > (dstlen - 1) {
                1
            } else {
                let csum = CString::new(sum).unwrap();
                unsafe {
                    strncpy(dst, csum.as_ptr() as *const i8, dstlen);
                }
                0
            }
        },
        Err(_) => {
            1
        }
    }
}

#[no_mangle]
pub extern fn rnc_sub(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) -> c_int {
    unsafe {
        match sub(CStr::from_ptr(num_l).to_str().unwrap(), CStr::from_ptr(num_r).to_str().unwrap()) {
            Ok(difference) => {
                //if sum.len() > (dstlen - 1) {
                //1
                //} else {
                let cdiff = CString::new(difference).unwrap();
                strncpy(dst, cdiff.as_ptr() as *const i8, dstlen);
                0
            },
            Err(_) => {
                1
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::os::raw::c_char;
use libc::size_t;
use libc::strncpy;

#[test]
fn add_i_i() {
    let actual_value = _add("I", "I");

    assert_eq!("II", actual_value);
}

#[test]
fn add_i_ii() {
    let actual_value = _add("I", "II");

    assert_eq!("III", actual_value);
}

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) {
    let x = _add("", "");

    unsafe {
        strncpy(dst, x.as_ptr() as *const i8, dstlen);
    }
}

fn _add(num_l: &str, num_r: &str) -> String {
    let sum = String::from(num_l);
    return sum + num_r;
}
<commit_msg>Fix compile errors in rust wrapper<commit_after>extern crate libc;

use std::ffi::CStr;
use std::os::raw::c_char;
use libc::size_t;
use libc::strncpy;

#[test]
fn add_i_i() {
    let actual_value = _add("I", "I");

    assert_eq!("II", actual_value);
}

#[test]
fn add_i_ii() {
    let actual_value = _add("I", "II");

    assert_eq!("III", actual_value);
}

#[no_mangle]
pub extern fn rnc_add(dst: *mut c_char, dstlen: size_t, num_l: *const c_char, num_r: *const c_char) {
    unsafe {
        let sum = _add(CStr::from_ptr(num_l).to_str().unwrap(), CStr::from_ptr(num_r).to_str().unwrap());
        strncpy(dst, sum.as_ptr() as *const i8, dstlen);
    }
}

fn _add(num_l: &str, num_r: &str) -> String {
    let sum = String::from(num_l);
    return sum + num_r;
}
<|endoftext|>


<commit_before>mod entities;
mod input;
mod updates;
mod util;

use chrono::{DateTime, Duration as OldDuration, Utc};
use log::{error, trace};
use rand_core::{OsRng, RngCore};
use serde_derive::Serialize;
use std::collections::HashMap;
use std::mem;

pub use self::entities::*;
pub use self::input::*;
pub use self::updates::*;
pub use self::util::*;

use crate::server::{ArenaId, ArenaLine, ArenaPoint, Direction, Player, PlayerId};

const ARENA_WIDTH: f64 = 560.0;
const ARENA_HEIGHT: f64 = 560.0;
const ARENA_MAX_PLAYERS: usize = 8;
const ARENA_START_TIMER_SECONDS: i64 = 1;
const LIGHTCYCLE_SPEED: f64 = 55.0;
// const LIGHTCYCLE_BRAKE_SPEED: f64 = 40.0;
// const LIGHTCYCLE_BOOST_SPEED: f64 = 70.0;

#[derive(Debug, Clone, Serialize)]
pub struct Arena {
    pub id: ArenaId,
    pub name: String,
    pub width: f64,
    pub height: f64,
    pub max_players: usize,

    pub started: Option<DateTime<Utc>>,

    pub players: HashMap<PlayerId, Player>,
    pub lightcycles: HashMap<PlayerId, Lightcycle>,
    pub lightribbons: HashMap<PlayerId, Lightribbon>,

    #[serde(skip)]
    pub updates: Vec<ArenaUpdate>,
    #[serde(skip)]
    updates_applied_so_far: usize,
}

impl Arena {
    pub fn with_name(name: &str) -> Self {
        Self {
            name: name.to_uppercase(),
            ..Default::default()
        }
    }

    pub fn add_player(&mut self, player: Player) {
        self.updates.push(ArenaUpdate::AddPlayer(player.id, player));
    }

    pub fn remove_player(&mut self, player_id: PlayerId) {
        self.updates.push(ArenaUpdate::RemovePlayer(player_id));
    }

    pub fn clear_updates(&mut self) {
        self.updates.clear();
        self.updates_applied_so_far = 0;
    }

    pub fn apply_updates(&mut self) -> &mut Self {
        let updates = mem::replace(&mut self.updates, Vec::new());
        for update in updates.iter().skip(self.updates_applied_so_far) {
            update.apply(self);
            self.updates_applied_so_far += 1;
        }
        mem::replace(&mut self.updates, updates);

        self
    }

    pub fn process_input(&mut self, player_id: PlayerId, input_event: ArenaInput) {
        input_event
            .process_into_updates(self, player_id)
            .drain(..)
            .for_each(|update| self.updates.push(update));
    }

    pub fn update(&mut self, delta_time: f64) {
        // apply process_input updates
        self.apply_updates();

        let started = match self.started {
            Some(started) => started,
            None => return,
        };

        let now = Utc::now();
        if now < started {
            return;
        }

        self.update_lightcycle_positions(delta_time)
            .apply_updates()
            .calculate_lightcycle_collisions(delta_time)
            .apply_updates()
            .update_lightribbon_positions()
            .apply_updates()
            .test_round_end()
            .apply_updates();
    }

    //
    // update helpers
    //

    fn update_lightcycle_positions(&mut self, delta_time: f64) -> &mut Self {
        for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue;
            };

            self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                *id,
                lightcycle.position
                    + lightcycle.direction.as_velocity() * lightcycle.speed * delta_time,
            ))
        }
        self
    }

    fn calculate_lightcycle_collisions(&mut self, delta_time: f64) -> &mut Self {
        'next_lightcycle: for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue 'next_lightcycle;
            };

            let last_position = lightcycle.position
                - lightcycle.direction.as_velocity() * lightcycle.speed * delta_time;

            let travelled = ArenaLine {
                from: last_position.to_untyped(),
                to: lightcycle.position.to_untyped(),
            };

            // test for lightribbon collisions
            for lightribbon in self.lightribbons.values() {
                for line in lightribbon.points.windows(2) {
                    let line = ArenaLine {
                        from: line[0].to_untyped(),
                        to: line[1].to_untyped(),
                    };

                    if travelled.overlaps_segment(&line) {
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }

                    if let Some(intersection) = travelled.intersection(&line) {
                        self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                            *id,
                            ArenaPoint::from_untyped(intersection),
                        ));
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }
                }
            }

            // test for arena bounds collisions
            if lightcycle.position.x < 0.0
                || lightcycle.position.y < 0.0
                || lightcycle.position.x > self.width
                || lightcycle.position.y > self.height
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }

            // test for collisions with other lightcycles
            if self
                .lightcycles
                .iter()
                .filter(|(_, other_lightcycle)| !other_lightcycle.dead)
                .filter(|(other_id, _)| id != *other_id)
                .any(|(_, other_lightcycle)| lightcycle.position == other_lightcycle.position)
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }
        }
        self
    }

    fn update_lightribbon_positions(&mut self) -> &mut Self {
        for id in self.lightribbons.keys() {
            let latest_point = match self.lightcycles.get(id) {
                Some(lightcycle) => {
                    if lightcycle.dead {
                        continue;
                    };

                    lightcycle.position
                }
                None => {
                    error!(
                        "Failed to update lightribbon position: No lightcycle with id {}",
                        id
                    );
                    continue;
                }
            };

            self.updates
                .push(ArenaUpdate::UpdateLightribbonReplaceLatestPoint(
                    *id,
                    latest_point,
                ));
        }
        self
    }

    fn test_round_end(&mut self) -> &mut Self {
        if self.lightcycles.values().all(|lightcycle| lightcycle.dead) {
            self.updates.push(ArenaUpdate::End);
        }
        self
    }
}

impl Default for Arena {
    fn default() -> Self {
        Self {
            id: Default::default(),
            name: Default::default(),
            width: ARENA_WIDTH,
            height: ARENA_HEIGHT,
            max_players: ARENA_MAX_PLAYERS,

            started: None,

            players: Default::default(),
            lightcycles: Default::default(),
            lightribbons: Default::default(),

            updates: Default::default(),
            updates_applied_so_far: 0,
        }
    }
}

/// ArenaOverview represents an overview of an Arena for the arena selection screen.
#[derive(Debug, Clone, Serialize)]
pub struct ArenaOverview {
    id: ArenaId,
    name: String,
    max_players: usize,
    started: Option<DateTime<Utc>>,
    players: HashMap<PlayerId, Player>,
}

impl From<&Arena> for ArenaOverview {
    fn from(arena: &Arena) -> Self {
        Self {
            id: arena.id,
            name: arena.name.clone(),
            max_players: arena.max_players,
            started: arena.started,
            players: arena.players.clone(),
        }
    }
}
<commit_msg>fixed unnecessary usage of mem::replace<commit_after>mod entities;
mod input;
mod updates;
mod util;

use chrono::{DateTime, Duration as OldDuration, Utc};
use log::{error, trace};
use rand_core::{OsRng, RngCore};
use serde_derive::Serialize;
use std::collections::HashMap;
use std::mem;

pub use self::entities::*;
pub use self::input::*;
pub use self::updates::*;
pub use self::util::*;

use crate::server::{ArenaId, ArenaLine, ArenaPoint, Direction, Player, PlayerId};

const ARENA_WIDTH: f64 = 560.0;
const ARENA_HEIGHT: f64 = 560.0;
const ARENA_MAX_PLAYERS: usize = 8;
const ARENA_START_TIMER_SECONDS: i64 = 1;
const LIGHTCYCLE_SPEED: f64 = 55.0;
// const LIGHTCYCLE_BRAKE_SPEED: f64 = 40.0;
// const LIGHTCYCLE_BOOST_SPEED: f64 = 70.0;

#[derive(Debug, Clone, Serialize)]
pub struct Arena {
    pub id: ArenaId,
    pub name: String,
    pub width: f64,
    pub height: f64,
    pub max_players: usize,

    pub started: Option<DateTime<Utc>>,

    pub players: HashMap<PlayerId, Player>,
    pub lightcycles: HashMap<PlayerId, Lightcycle>,
    pub lightribbons: HashMap<PlayerId, Lightribbon>,

    #[serde(skip)]
    pub updates: Vec<ArenaUpdate>,
    #[serde(skip)]
    updates_applied_so_far: usize,
}

impl Arena {
    pub fn with_name(name: &str) -> Self {
        Self {
            name: name.to_uppercase(),
            ..Default::default()
        }
    }

    pub fn add_player(&mut self, player: Player) {
        self.updates.push(ArenaUpdate::AddPlayer(player.id, player));
    }

    pub fn remove_player(&mut self, player_id: PlayerId) {
        self.updates.push(ArenaUpdate::RemovePlayer(player_id));
    }

    pub fn clear_updates(&mut self) {
        self.updates.clear();
        self.updates_applied_so_far = 0;
    }

    pub fn apply_updates(&mut self) -> &mut Self {
        let updates = mem::take(&mut self.updates);
        for update in updates.iter().skip(self.updates_applied_so_far) {
            update.apply(self);
            self.updates_applied_so_far += 1;
        }
        self.updates = updates;

        self
    }

    pub fn process_input(&mut self, player_id: PlayerId, input_event: ArenaInput) {
        input_event
            .process_into_updates(self, player_id)
            .drain(..)
            .for_each(|update| self.updates.push(update));
    }

    pub fn update(&mut self, delta_time: f64) {
        // apply process_input updates
        self.apply_updates();

        let started = match self.started {
            Some(started) => started,
            None => return,
        };

        let now = Utc::now();
        if now < started {
            return;
        }

        self.update_lightcycle_positions(delta_time)
            .apply_updates()
            .calculate_lightcycle_collisions(delta_time)
            .apply_updates()
            .update_lightribbon_positions()
            .apply_updates()
            .test_round_end()
            .apply_updates();
    }

    //
    // update helpers
    //

    fn update_lightcycle_positions(&mut self, delta_time: f64) -> &mut Self {
        for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue;
            };

            self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                *id,
                lightcycle.position
                    + lightcycle.direction.as_velocity() * lightcycle.speed * delta_time,
            ))
        }
        self
    }

    fn calculate_lightcycle_collisions(&mut self, delta_time: f64) -> &mut Self {
        'next_lightcycle: for (id, lightcycle) in self.lightcycles.iter() {
            if lightcycle.dead {
                continue 'next_lightcycle;
            };

            let last_position = lightcycle.position
                - lightcycle.direction.as_velocity() * lightcycle.speed * delta_time;

            let travelled = ArenaLine {
                from: last_position.to_untyped(),
                to: lightcycle.position.to_untyped(),
            };

            // test for lightribbon collisions
            for lightribbon in self.lightribbons.values() {
                for line in lightribbon.points.windows(2) {
                    let line = ArenaLine {
                        from: line[0].to_untyped(),
                        to: line[1].to_untyped(),
                    };

                    if travelled.overlaps_segment(&line) {
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }

                    if let Some(intersection) = travelled.intersection(&line) {
                        self.updates.push(ArenaUpdate::UpdateLightcyclePosition(
                            *id,
                            ArenaPoint::from_untyped(intersection),
                        ));
                        self.updates
                            .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                        continue 'next_lightcycle;
                    }
                }
            }

            // test for arena bounds collisions
            if lightcycle.position.x < 0.0
                || lightcycle.position.y < 0.0
                || lightcycle.position.x > self.width
                || lightcycle.position.y > self.height
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }

            // test for collisions with other lightcycles
            if self
                .lightcycles
                .iter()
                .filter(|(_, other_lightcycle)| !other_lightcycle.dead)
                .filter(|(other_id, _)| id != *other_id)
                .any(|(_, other_lightcycle)| lightcycle.position == other_lightcycle.position)
            {
                self.updates
                    .push(ArenaUpdate::UpdateLightcycleApplyDeath(*id));
                continue 'next_lightcycle;
            }
        }
        self
    }

    fn update_lightribbon_positions(&mut self) -> &mut Self {
        for id in self.lightribbons.keys() {
            let latest_point = match self.lightcycles.get(id) {
                Some(lightcycle) => {
                    if lightcycle.dead {
                        continue;
                    };

                    lightcycle.position
                }
                None => {
                    error!(
                        "Failed to update lightribbon position: No lightcycle with id {}",
                        id
                    );
                    continue;
                }
            };

            self.updates
                .push(ArenaUpdate::UpdateLightribbonReplaceLatestPoint(
                    *id,
                    latest_point,
                ));
        }
        self
    }

    fn test_round_end(&mut self) -> &mut Self {
        if self.lightcycles.values().all(|lightcycle| lightcycle.dead) {
            self.updates.push(ArenaUpdate::End);
        }
        self
    }
}

impl Default for Arena {
    fn default() -> Self {
        Self {
            id: Default::default(),
            name: Default::default(),
            width: ARENA_WIDTH,
            height: ARENA_HEIGHT,
            max_players: ARENA_MAX_PLAYERS,

            started: None,

            players: Default::default(),
            lightcycles: Default::default(),
            lightribbons: Default::default(),

            updates: Default::default(),
            updates_applied_so_far: 0,
        }
    }
}

/// ArenaOverview represents an overview of an Arena for the arena selection screen.
#[derive(Debug, Clone, Serialize)]
pub struct ArenaOverview {
    id: ArenaId,
    name: String,
    max_players: usize,
    started: Option<DateTime<Utc>>,
    players: HashMap<PlayerId, Player>,
}

impl From<&Arena> for ArenaOverview {
    fn from(arena: &Arena) -> Self {
        Self {
            id: arena.id,
            name: arena.name.clone(),
            max_players: arena.max_players,
            started: arena.started,
            players: arena.players.clone(),
        }
    }
}
<|endoftext|>


<commit_before>//! Luminance (base unit candela per square meter, cd · m⁻²).

quantity! {
    /// Luminance (base unit candela per square meter, cd · m⁻²).
    quantity: Luminance; "luminance";
    /// Dimension of luminance, L⁻²J (base unit candela per square meter, cd · m⁻²).
    dimension: ISQ<
        N2,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        P1>;    // luminous intensity
    units {
        @yottacandela_per_square_meter: prefix!(yotta); "Ycd/m²", "yottacandela per square meter",
            "yottacandelas per square meter";
        @zettacandela_per_square_meter: prefix!(zetta); "Zcd/m²", "zettacandela per square meter",
            "zettacandelas per square meter";
        @exacandela_per_square_meter: prefix!(exa); "Ecd/m²", "exacandela per square meter",
            "exacandelas per square meter";
        @petacandela_per_square_meter: prefix!(peta); "Pcd/m²", "petacandela per square meter",
            "petacandelas per square meter";
        @teracandela_per_square_meter: prefix!(tera); "Tcd/m²", "teracandela per square meter",
            "teracandelas per square meter";
        @gigacandela_per_square_meter: prefix!(giga); "Gcd/m²", "gigacandela per square meter",
            "gigacandelas per square meter";
        @megacandela_per_square_meter: prefix!(mega); "Mcd/m²", "megacandela per square meter",
            "megacandelas per square meter";
        @kilocandela_per_square_meter: prefix!(kilo); "kcd/m²", "kilocandela per square meter",
            "kilocandelas per square meter";
        @hectocandela_per_square_meter: prefix!(hecto); "hcd/m²", "hectocandela per square meter",
            "hectocandelas per square meter";
        @decacandela_per_square_meter: prefix!(deca); "dacd/m²", "decacandela per square meter",
            "decacandelas per square meter";
        /// Derived unit of luminance.
        @candela_per_square_meter: prefix!(none); "cd/m²", "candela per square meter",
            "candelas per square meter";
        @decicandela_per_square_meter: prefix!(deci); "dcd/m²", "decicandela per square meter",
            "decicandelas per square meter";
        @centicandela_per_square_meter: prefix!(centi); "ccd/m²", "centicandela per square meter",
            "centicandelas per square meter";
        @millicandela_per_square_meter: prefix!(milli); "mcd/m²", "millicandela per square meter",
            "millicandelas per square meter";
        @microcandela_per_square_meter: prefix!(micro); "µcd/m²", "microcandela per square meter",
            "microcandelas per square meter";
        @nanocandela_per_square_meter: prefix!(nano); "ncd/m²", "nanocandela per square meter",
            "nanocandelas per square meter";
        @picocandela_per_square_meter: prefix!(pico); "pcd/m²", "picocandela per square meter",
            "picocandelas per square meter";
        @femtocandela_per_square_meter: prefix!(femto); "fcd/m²", "femtocandela per square meter",
            "femtocandelas per square meter";
        @attocandela_per_square_meter: prefix!(atto); "acd/m²", "attocandela per square meter",
            "attocandelas per square meter";
        @zeptocandela_per_square_meter: prefix!(zepto); "zcd/m²", "zeptocandela per square meter",
            "zeptocandelas per square meter";
        @yoctocandela_per_square_meter: prefix!(yocto); "ycd/m²", "yoctocandela per square meter",
            "yoctocandelas per square meter";

        @candela_per_square_picometer: prefix!(yotta); "cd/pm²", "candela per square picometer",
            "candelas per square picometer";
        @candela_per_square_nanometer: prefix!(exa); "cd/nm²", "candela per square nanometer",
            "candelas per square nanometer";
        @candela_per_square_micrometer: prefix!(tera); "cd/µm²", "candela per square micrometer",
            "candelas per square micrometer";
        @candela_per_square_millimeter: prefix!(mega); "cd/mm²", "candela per square millimeter",
            "candelas per square millimeter";
        @candela_per_square_centimeter: 1.0_E4; "cd/cm²", "candela per square centimeter",
            "candelas per square centimeter";
        @candela_per_square_kilometer: prefix!(micro); "cd/km²", "candela per square kilometer",
            "candelas per square kilometer";
        @candela_per_square_megameter: prefix!(pico); "cd/Mm²", "candela per square megameter",
            "candelas per square megameter";
        @candela_per_square_gigameter: prefix!(atto); "cd/Gm²", "candela per square gigameter",
            "candelas per square gigameter";
        @candela_per_square_terameter: prefix!(yocto); "cd/Tm²", "candela per square terameter",
            "candelas per square terameter";

        @candela_per_square_inch: 1.550_003_100_006_200_2_E3; "cd/in²", "candela per square inch",
            "candelas per square inch";
        @footlambert: 3.426_259_099_635_390_5_E0; "fl", "footlambert", "footlamberts";
        @lambert: 3.183_098_861_837_906_7_E3; "la", "lambert", "lamberts";
        @stilb: 1.0_E4; "sb", "stilb", "stilbs";
    }
}

#[cfg(test)]
mod test {
    storage_types! {
        use num::One;
        use si::quantities::*;
        use si::luminous_intensity as i;
        use si::area as a;
        use si::luminance as l;
        use tests::Test;

        #[test]
        fn check_dimension() {
            let _: Luminance<V> = LuminousIntensity::new::<i::candela>(V::one())
                / Area::new::<a::square_meter>(V::one());
        }

        #[test]
        fn check_units() {
            test::<i::yottacandela, a::square_meter, l::yottacandela_per_square_meter>();
            test::<i::zettacandela, a::square_meter, l::zettacandela_per_square_meter>();
            test::<i::exacandela, a::square_meter, l::exacandela_per_square_meter>();
            test::<i::petacandela, a::square_meter, l::petacandela_per_square_meter>();
            test::<i::teracandela, a::square_meter, l::teracandela_per_square_meter>();
            test::<i::gigacandela, a::square_meter, l::gigacandela_per_square_meter>();
            test::<i::megacandela, a::square_meter, l::megacandela_per_square_meter>();
            test::<i::kilocandela, a::square_meter, l::kilocandela_per_square_meter>();
            test::<i::hectocandela, a::square_meter, l::hectocandela_per_square_meter>();
            test::<i::decacandela, a::square_meter, l::decacandela_per_square_meter>();
            test::<i::candela, a::square_meter, l::candela_per_square_meter>();
            test::<i::decicandela, a::square_meter, l::decicandela_per_square_meter>();
            test::<i::centicandela, a::square_meter, l::centicandela_per_square_meter>();
            test::<i::millicandela, a::square_meter, l::millicandela_per_square_meter>();
            test::<i::microcandela, a::square_meter, l::microcandela_per_square_meter>();
            test::<i::nanocandela, a::square_meter, l::nanocandela_per_square_meter>();
            test::<i::picocandela, a::square_meter, l::picocandela_per_square_meter>();
            test::<i::femtocandela, a::square_meter, l::femtocandela_per_square_meter>();
            test::<i::attocandela, a::square_meter, l::attocandela_per_square_meter>();
            test::<i::zeptocandela, a::square_meter, l::zeptocandela_per_square_meter>();
            test::<i::yoctocandela, a::square_meter, l::yoctocandela_per_square_meter>();

            test::<i::candela, a::square_picometer, l::candela_per_square_picometer>();
            test::<i::candela, a::square_nanometer, l::candela_per_square_nanometer>();
            test::<i::candela, a::square_micrometer, l::candela_per_square_micrometer>();
            test::<i::candela, a::square_millimeter, l::candela_per_square_millimeter>();
            test::<i::candela, a::square_centimeter, l::candela_per_square_centimeter>();
            test::<i::candela, a::square_kilometer, l::candela_per_square_kilometer>();
            test::<i::candela, a::square_megameter, l::candela_per_square_megameter>();
            test::<i::candela, a::square_gigameter, l::candela_per_square_gigameter>();
            test::<i::candela, a::square_terameter, l::candela_per_square_terameter>();

            test::<i::candela, a::square_inch, l::candela_per_square_inch>();

            fn test<I: i::Conversion<V>, A: a::Conversion<V>, L: l::Conversion<V>>() {
                Test::assert_approx_eq(&Luminance::new::<L>(V::one()),
                    &(LuminousIntensity::new::<I>(V::one()) / Area::new::<A>(V::one())));
            }
        }
    }
}
<commit_msg>Added foot-candle unit to luminance<commit_after>//! Luminance (base unit candela per square meter, cd · m⁻²).

quantity! {
    /// Luminance (base unit candela per square meter, cd · m⁻²).
    quantity: Luminance; "luminance";
    /// Dimension of luminance, L⁻²J (base unit candela per square meter, cd · m⁻²).
    dimension: ISQ<
        N2,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        P1>;    // luminous intensity
    units {
        @yottacandela_per_square_meter: prefix!(yotta); "Ycd/m²", "yottacandela per square meter",
            "yottacandelas per square meter";
        @zettacandela_per_square_meter: prefix!(zetta); "Zcd/m²", "zettacandela per square meter",
            "zettacandelas per square meter";
        @exacandela_per_square_meter: prefix!(exa); "Ecd/m²", "exacandela per square meter",
            "exacandelas per square meter";
        @petacandela_per_square_meter: prefix!(peta); "Pcd/m²", "petacandela per square meter",
            "petacandelas per square meter";
        @teracandela_per_square_meter: prefix!(tera); "Tcd/m²", "teracandela per square meter",
            "teracandelas per square meter";
        @gigacandela_per_square_meter: prefix!(giga); "Gcd/m²", "gigacandela per square meter",
            "gigacandelas per square meter";
        @megacandela_per_square_meter: prefix!(mega); "Mcd/m²", "megacandela per square meter",
            "megacandelas per square meter";
        @kilocandela_per_square_meter: prefix!(kilo); "kcd/m²", "kilocandela per square meter",
            "kilocandelas per square meter";
        @hectocandela_per_square_meter: prefix!(hecto); "hcd/m²", "hectocandela per square meter",
            "hectocandelas per square meter";
        @decacandela_per_square_meter: prefix!(deca); "dacd/m²", "decacandela per square meter",
            "decacandelas per square meter";
        /// Derived unit of luminance.
        @candela_per_square_meter: prefix!(none); "cd/m²", "candela per square meter",
            "candelas per square meter";
        @decicandela_per_square_meter: prefix!(deci); "dcd/m²", "decicandela per square meter",
            "decicandelas per square meter";
        @centicandela_per_square_meter: prefix!(centi); "ccd/m²", "centicandela per square meter",
            "centicandelas per square meter";
        @millicandela_per_square_meter: prefix!(milli); "mcd/m²", "millicandela per square meter",
            "millicandelas per square meter";
        @microcandela_per_square_meter: prefix!(micro); "µcd/m²", "microcandela per square meter",
            "microcandelas per square meter";
        @nanocandela_per_square_meter: prefix!(nano); "ncd/m²", "nanocandela per square meter",
            "nanocandelas per square meter";
        @picocandela_per_square_meter: prefix!(pico); "pcd/m²", "picocandela per square meter",
            "picocandelas per square meter";
        @femtocandela_per_square_meter: prefix!(femto); "fcd/m²", "femtocandela per square meter",
            "femtocandelas per square meter";
        @attocandela_per_square_meter: prefix!(atto); "acd/m²", "attocandela per square meter",
            "attocandelas per square meter";
        @zeptocandela_per_square_meter: prefix!(zepto); "zcd/m²", "zeptocandela per square meter",
            "zeptocandelas per square meter";
        @yoctocandela_per_square_meter: prefix!(yocto); "ycd/m²", "yoctocandela per square meter",
            "yoctocandelas per square meter";

        @candela_per_square_picometer: prefix!(yotta); "cd/pm²", "candela per square picometer",
            "candelas per square picometer";
        @candela_per_square_nanometer: prefix!(exa); "cd/nm²", "candela per square nanometer",
            "candelas per square nanometer";
        @candela_per_square_micrometer: prefix!(tera); "cd/µm²", "candela per square micrometer",
            "candelas per square micrometer";
        @candela_per_square_millimeter: prefix!(mega); "cd/mm²", "candela per square millimeter",
            "candelas per square millimeter";
        @candela_per_square_centimeter: 1.0_E4; "cd/cm²", "candela per square centimeter",
            "candelas per square centimeter";
        @candela_per_square_kilometer: prefix!(micro); "cd/km²", "candela per square kilometer",
            "candelas per square kilometer";
        @candela_per_square_megameter: prefix!(pico); "cd/Mm²", "candela per square megameter",
            "candelas per square megameter";
        @candela_per_square_gigameter: prefix!(atto); "cd/Gm²", "candela per square gigameter",
            "candelas per square gigameter";
        @candela_per_square_terameter: prefix!(yocto); "cd/Tm²", "candela per square terameter",
            "candelas per square terameter";

        @candela_per_square_inch: 1.550_003_100_006_200_2_E3; "cd/in²", "candela per square inch",
            "candelas per square inch";
        @candela_per_square_foot: 1.076_391_041_670_972_2_E1; "cd/ft²", "candela per square foot",
            "candelas per square foot";
        @footlambert: 3.426_259_099_635_390_5_E0; "fl", "footlambert", "footlamberts";
        @lambert: 3.183_098_861_837_906_7_E3; "la", "lambert", "lamberts";
        @stilb: 1.0_E4; "sb", "stilb", "stilbs";
    }
}

#[cfg(test)]
mod test {
    storage_types! {
        use num::One;
        use si::quantities::*;
        use si::luminous_intensity as i;
        use si::area as a;
        use si::luminance as l;
        use tests::Test;

        #[test]
        fn check_dimension() {
            let _: Luminance<V> = LuminousIntensity::new::<i::candela>(V::one())
                / Area::new::<a::square_meter>(V::one());
        }

        #[test]
        fn check_units() {
            test::<i::yottacandela, a::square_meter, l::yottacandela_per_square_meter>();
            test::<i::zettacandela, a::square_meter, l::zettacandela_per_square_meter>();
            test::<i::exacandela, a::square_meter, l::exacandela_per_square_meter>();
            test::<i::petacandela, a::square_meter, l::petacandela_per_square_meter>();
            test::<i::teracandela, a::square_meter, l::teracandela_per_square_meter>();
            test::<i::gigacandela, a::square_meter, l::gigacandela_per_square_meter>();
            test::<i::megacandela, a::square_meter, l::megacandela_per_square_meter>();
            test::<i::kilocandela, a::square_meter, l::kilocandela_per_square_meter>();
            test::<i::hectocandela, a::square_meter, l::hectocandela_per_square_meter>();
            test::<i::decacandela, a::square_meter, l::decacandela_per_square_meter>();
            test::<i::candela, a::square_meter, l::candela_per_square_meter>();
            test::<i::decicandela, a::square_meter, l::decicandela_per_square_meter>();
            test::<i::centicandela, a::square_meter, l::centicandela_per_square_meter>();
            test::<i::millicandela, a::square_meter, l::millicandela_per_square_meter>();
            test::<i::microcandela, a::square_meter, l::microcandela_per_square_meter>();
            test::<i::nanocandela, a::square_meter, l::nanocandela_per_square_meter>();
            test::<i::picocandela, a::square_meter, l::picocandela_per_square_meter>();
            test::<i::femtocandela, a::square_meter, l::femtocandela_per_square_meter>();
            test::<i::attocandela, a::square_meter, l::attocandela_per_square_meter>();
            test::<i::zeptocandela, a::square_meter, l::zeptocandela_per_square_meter>();
            test::<i::yoctocandela, a::square_meter, l::yoctocandela_per_square_meter>();

            test::<i::candela, a::square_picometer, l::candela_per_square_picometer>();
            test::<i::candela, a::square_nanometer, l::candela_per_square_nanometer>();
            test::<i::candela, a::square_micrometer, l::candela_per_square_micrometer>();
            test::<i::candela, a::square_millimeter, l::candela_per_square_millimeter>();
            test::<i::candela, a::square_centimeter, l::candela_per_square_centimeter>();
            test::<i::candela, a::square_kilometer, l::candela_per_square_kilometer>();
            test::<i::candela, a::square_megameter, l::candela_per_square_megameter>();
            test::<i::candela, a::square_gigameter, l::candela_per_square_gigameter>();
            test::<i::candela, a::square_terameter, l::candela_per_square_terameter>();

            test::<i::candela, a::square_inch, l::candela_per_square_inch>();
            test::<i::candela, a::square_foot, l::candela_per_square_foot>();

            fn test<I: i::Conversion<V>, A: a::Conversion<V>, L: l::Conversion<V>>() {
                Test::assert_approx_eq(&Luminance::new::<L>(V::one()),
                    &(LuminousIntensity::new::<I>(V::one()) / Area::new::<A>(V::one())));
            }
        }
    }
}
<|endoftext|>


<commit_before>use scene::{BoxedScene, Scene, SceneChangeEvent, SceneName};
use text_renderer::TextRenderer;
use sdl2::pixels::Color;
use std::io::Result;
use std::path::Path;
use uorustlibs::skills::Skills;

use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2_ttf::Font;

pub struct SkillsScene {
    text: Texture
}

impl SkillsScene {
    pub fn new(text_renderer: &TextRenderer, renderer: &mut Renderer) -> BoxedScene<SceneName> {
        let skills = Skills::new(&Path::new("./assets/skills.idx"), &Path::new("./assets/skills.mul"));
        let text = match skills {
            Ok(skills) => {
                let items: Vec<String> = skills.skills.iter().map(|skill| {
                    let glyph = if skill.clickable {
                        "+"
                    } else {
                        "-"
                    };
                    format!("{} {}", glyph, skill.name)
                }).collect();
                items.join("\n")
            },
            Err(error) => {
                format!("{}", error)
            }
        };
        Box::new(SkillsScene {
            text: text_renderer.create_text(renderer, &text, Color::RGBA(255, 255, 255, 255))
        })
    }

    /*fn render(&mut self, _args: RenderArgs, uic: &mut UiContext, gl: &mut Gl) {
        gl.enable_alpha_blend();
        uic.background().color(Color::black()).draw(gl);
        match self.skills {
            Ok(ref skills) => {
                for (idx, skill) in skills.skills.iter().enumerate() {
                    let glyph = if skill.clickable {
                        "+"
                    } else {
                        "-"
                    };
                    uic.label(format!("{} {}", glyph, skill.name).as_slice())
                        .position(((idx / 20) * 256) as f64, ((idx % 20) * 16) as f64)
                        .size(16u32)
                        .color(Color::white())
                        .draw(gl);
                }
            },
            Err(ref error) => {
                uic.label(format!("{}", error).as_slice())
                    .position(0.0, 0.0)
                    .size(16u32)
                    .color(Color::white())
                    .draw(gl);
            }
        }
    }*/
}

impl<T> Scene<T> for SkillsScene {
    fn render(&self, renderer: &mut Renderer) {
        let TextureQuery {width, height, .. } = self.text.query();
        let target = Rect::new(0, 0, width, height);
        renderer.clear();
        renderer.copy(&self.text, None, Some(target)).unwrap();
        renderer.present();
    }

    fn handle_event(&self, event: &Event) -> Option<SceneChangeEvent<T>> {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                Some(SceneChangeEvent::PopScene)
            },
            Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
                println!("2");
                None
            },
             _ => None
        }
    }
}
<commit_msg>src/[A<commit_after>use scene::{BoxedScene, Scene, SceneChangeEvent, SceneName};
use text_renderer::TextRenderer;
use sdl2::pixels::Color;
use std::io::Result;
use std::path::Path;
use uorustlibs::skills::Skills;

use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2_ttf::Font;

pub struct SkillsScene {
    pages: Vec<Texture>,
}

impl SkillsScene {
    pub fn new(text_renderer: &TextRenderer, renderer: &mut Renderer) -> BoxedScene<SceneName> {
        let skills = Skills::new(&Path::new("./assets/skills.idx"), &Path::new("./assets/skills.mul"));
        let text = match skills {
            Ok(skills) => {
                let items: Vec<Texture> = skills.skills.chunks(30).map(|chunk| {
                    let skills: Vec<String> = chunk.iter().map(|skill| {
                        let glyph = if skill.clickable {
                            "+"
                        } else {
                            "-"
                        };
                        format!("{} {}", glyph, skill.name)
                    }).collect();
                    text_renderer.create_text(renderer, &skills.join("\n"), Color::RGBA(255, 255, 255, 255))
                }).collect();
                items
            },
            Err(error) => {
                let text = format!("{}", error);
                let texture = text_renderer.create_text(renderer, &text, Color::RGBA(255, 255, 255, 255));
                vec![texture]
            }
        };
        Box::new(SkillsScene {
            pages: text,
        })
    }
}

impl<T> Scene<T> for SkillsScene {
    fn render(&self, renderer: &mut Renderer) {
        renderer.clear();
        let mut last_width = 0;
        for page in self.pages.iter() {
            let TextureQuery {width, height, .. } = page.query();
            let target = Rect::new(last_width, 0, width, height);
            renderer.copy(page, None, Some(target)).unwrap();
            last_width += width;
        }
        renderer.present();
    }

    fn handle_event(&self, event: &Event) -> Option<SceneChangeEvent<T>> {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                Some(SceneChangeEvent::PopScene)
            },
            Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
                println!("2");
                None
            },
             _ => None
        }
    }
}
<|endoftext|>


<commit_before>// TODO: This will panic on certain opcodes. The ideas I have for cpu_lang
// will probably fix it; we'll see. For now tho, I'm gonna leave it as-is;
// I can imagine fixing it trivially might lead to performance problems.
// I'll deal with it after the port is finished.

// TODO: This is a placeholder before I start generalizing traits
// from the old code.
use super::apu::Apu;

pub struct Smp<'a> {
    emulator: &'a mut Apu,

    reg_pc: u16,
    reg_a: u8,
    reg_x: u8,
    reg_y: u8,
    reg_sp: u8,

    psw_c: bool,
    psw_z: bool,
    psw_h: bool,
    psw_p: bool,
    psw_v: bool,
    psw_n: bool,
    // TODO: Look up some more behavior for I and B. Can't seem to find much
    // but some instructions DO set them.
    psw_i: bool,
    psw_b: bool,

    cycle_count: i32
}

impl<'a> Smp<'a> {
    pub fn new(emulator: &'a mut Apu) -> Smp<'a> {
        let mut ret = Smp {
            emulator: emulator,

            reg_pc: 0,
            reg_a: 0,
            reg_x: 0,
            reg_y: 0,
            reg_sp: 0,

            psw_c: false,
            psw_z: false,
            psw_h: false,
            psw_p: false,
            psw_v: false,
            psw_n: false,
            psw_i: false,
            psw_b: false,

            cycle_count: 0
        };
        ret.reset();
        ret
    }

    pub fn reset(&mut self) {
        self.reg_pc = 0xffc0;
        self.reg_a = 0;
        self.reg_x = 0;
        self.reg_y = 0;
        self.reg_sp = 0xef;
        self.set_psw(0x02);
    }

    pub fn set_reg_ya(&mut self, value: u16) {
        self.reg_a = (value & 0xff) as u8;
        self.reg_y = ((value >> 8) & 0xff) as u8;
    }

    pub fn get_reg_ya(&self) -> u16 {
        ((self.reg_y as u16) << 8) | (self.reg_a as u16)
    }

    pub fn set_psw(&mut self, value: u8) {
        self.psw_c = (value & 0x01) != 0;
        self.psw_z = (value & 0x02) != 0;
        self.psw_h = (value & 0x08) != 0;
        self.psw_p = (value & 0x20) != 0;
        self.psw_v = (value & 0x40) != 0;
        self.psw_n = (value & 0x80) != 0;
    }

    pub fn get_psw(&self) -> u8 {
        ((if self.psw_n { 1 } else { 0 }) << 7) |
        ((if self.psw_v { 1 } else { 0 }) << 6) |
        ((if self.psw_p { 1 } else { 0 }) << 5) |
        ((if self.psw_h { 1 } else { 0 }) << 3) |
        ((if self.psw_z { 1 } else { 0 }) << 1) |
        (if self.psw_c { 1 } else { 0 })
    }

    fn is_negative(value: u32) -> bool {
        (value & 0x80) != 0
    }

    fn cycles(&mut self, num_cycles: i32) {
        self.emulator.cpu_cycles_callback(num_cycles);
        self.cycle_count += num_cycles;
    }

    fn read_op(&mut self, addr: u16) -> u8 {
        self.cycles(1);
        self.emulator.read_byte(addr as u32)
    }

    fn write_op(&mut self, addr: u16, value: u8) {
        self.cycles(1);
        self.emulator.write_byte(addr as u32, value);
    }

    fn read_pc_op(&mut self) -> u8 {
        let addr = self.reg_pc;
        self.reg_pc += 1;
        let ret = self.read_op(addr);
        ret
    }

    fn read_sp_op(&mut self) -> u8 {
        self.reg_sp += 1;
        let addr = 0x0100 | (self.reg_sp as u16);
        self.read_op(addr)
    }

    fn write_sp_op(&mut self, value: u8) {
        let addr = 0x0100 | (self.reg_sp as u16);
        self.reg_sp -= 1;
        self.write_op(addr, value);
    }

    fn read_dp_op(&mut self, addr: u8) -> u8 {
        let addr = (if self.psw_p { 0x0100 } else { 0 }) | (addr as u16);
        self.read_op(addr)
    }

    fn write_dp_op(&mut self, addr: u8, value: u8) {
        let addr = (if self.psw_p { 0x0100 } else { 0 }) | (addr as u16);
        self.write_op(addr, value);
    }

    fn set_psw_n_z_op(&mut self, x: u32) {
        self.psw_n = Smp::is_negative(x);
        self.psw_z = x == 0;
    }

    fn adc_op(&mut self, x: u8, y: u8) -> u8 {
        let x = x as u32;
        let y = y as u32;
        let r = x + y + (if self.psw_c { 1 } else { 0 });
        self.psw_n = Smp::is_negative(r);
        self.psw_v = (!(x ^ y) & (x ^ r) & 0x80) != 0;
        self.psw_h = ((x ^ y ^ r) & 0x10) != 0;
        self.psw_z = (r & 0xff) == 0;
        self.psw_c = r > 0xff;
        (r & 0xff) as u8
    }

    fn and_op(&mut self, x: u8, y: u8) -> u8 {
        let ret = x & y;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn asl_op(&mut self, x: u8) -> u8 {
        self.psw_c = Smp::is_negative(x as u32);
        let ret = x << 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn cmp_op(&mut self, x: u8, y: u8) -> u8 {
        let r = (x as i32) - (y as i32);
        self.psw_n = (r & 0x80) != 0;
        self.psw_z = (r & 0xff) == 0;
        self.psw_c = r >= 0;
        x
    }

    fn dec_op(&mut self, x: u8) -> u8 {
        let ret = x - 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn eor_op(&mut self, x: u8, y: u8) -> u8 {
        let ret = x ^ y;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn inc_op(&mut self, x: u8) -> u8 {
        let ret = x + 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn ld_op(&mut self, _: u8, y: u8) -> u8 {
        self.set_psw_n_z_op(y as u32);
        y
    }

    fn lsr_op(&mut self, x: u8) -> u8 {
        self.psw_c = (x & 0x01) != 0;
        let ret = x >> 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn or_op(&mut self, x: u8, y: u8) -> u8 {
        let ret = x | y;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn rol_op(&mut self, x: u8) -> u8 {
        let carry = if self.psw_c { 1 } else { 0 };
        self.psw_c = (x & 0x80) != 0;
        let ret = (x << 1) | carry;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn ror_op(&mut self, x: u8) -> u8 {
        let carry = if self.psw_c { 0x80 } else { 0 };
        self.psw_c = (x & 0x01) != 0;
        let ret = carry | (x >> 1);
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn sbc_op(&mut self, x: u8, y: u8) -> u8 {
        self.adc_op(x, !y)
    }

    fn st_op(&self, _: u8, y: u8) -> u8 {
        y
    }

    fn adw_op(&mut self, x: u16, y: u16) -> u16 {
        self.psw_c = false;
        let mut ret = self.adc_op(x as u8, y as u8) as u16;
        ret |= (self.adc_op((x >> 8) as u8, (y >> 8) as u8) as u16) << 8;
        self.psw_z = ret == 0;
        ret
    }

    fn cpw_op(&mut self, x: u16, y: u16) -> u16 {
        let ret = (x as i32) - (y as i32);
        self.psw_n = (ret & 0x8000) != 0;
        self.psw_z = (ret as u16) == 0;
        self.psw_c = ret >= 0;
        ret as u16
    }

    fn ldw_op(&mut self, _: u16, y: u16) -> u16 {
        self.psw_n = (y & 0x8000) != 0;
        self.psw_z = y == 0;
        y
    }

    fn sbw_op(&mut self, x: u16, y: u16) -> u16 {
        self.psw_c = true;
        let mut ret = self.sbc_op(x as u8, y as u8) as u16;
        ret |= (self.sbc_op((x >> 8) as u8, (y >> 8) as u8) as u16) << 8;
        self.psw_z = ret == 0;
        ret
    }

    fn adjust_dpw_op(&mut self, x: u16) {
        let mut addr = self.read_pc_op();
        let mut result = (self.read_dp_op(addr) as u16) + x;
        self.write_dp_op(addr, result as u8);
        addr += 1;
        let mut high = (result >> 8) as u8;
        high += self.read_dp_op(addr);
        result = ((high as u16) << 8) | (result & 0xff);
        self.write_dp_op(addr, (result >> 8) as u8);
        self.psw_n = (result & 0x8000) != 0;
        self.psw_z = result == 0;
    }

    fn branch_op(&mut self, cond: bool) {
        let offset = self.read_pc_op();
        if !cond {
            return;
        }
        self.cycles(2);
        // TODO: Some of these casts might not be necessary; there's probably
        // a better way to add a i8 to a u16 with proper signs.
        self.reg_pc = ((self.reg_pc as i16) + ((offset as i8) as i16)) as u16;
    }

    fn run(&mut self, target_cycles: i32) -> i32 {
        macro_rules! adjust_op {
            ($op:ident, $x:ident) => ({
                self.cycles(1);
                $x = self.$op($x);
            })
        }

        macro_rules! adjust_addr_op {
            ($op:ident) => ({
                let mut addr = self.read_pc_op() as u16;
                addr |= (self.read_pc_op() as u16) << 8;
                let mut result = self.read_op(addr);
                result = self.$op(result);
                self.write_op(addr, result);
            })
        }

        macro_rules! adjust_dp_op {
            ($op:ident) => ({
                let addr = self.read_pc_op() as u16;
                let mut result = self.read_dp_op(addr);
                result = self.$op(result);
                self.write_dp_op(addr, result);
            })
        }

        macro_rules! adjust_dp_x_op {
            ($op:ident) => ({
                let addr = self.read_pc_op();
                self.cycles(1);
                let mut result = self.read_dp_op(addr + self.reg_x);
                result = self.$op(result);
                self.write_dp_op(addr + self.reg_x, result);
            })
        }

        0 // TODO
    }
}
<commit_msg>so many ops<commit_after>// TODO: This will panic on certain opcodes. The ideas I have for cpu_lang
// will probably fix it; we'll see. For now tho, I'm gonna leave it as-is;
// I can imagine fixing it trivially might lead to performance problems.
// I'll deal with it after the port is finished.

// TODO: This is a placeholder before I start generalizing traits
// from the old code.
use super::apu::Apu;

pub struct Smp<'a> {
    emulator: &'a mut Apu,

    reg_pc: u16,
    reg_a: u8,
    reg_x: u8,
    reg_y: u8,
    reg_sp: u8,

    psw_c: bool,
    psw_z: bool,
    psw_h: bool,
    psw_p: bool,
    psw_v: bool,
    psw_n: bool,
    // TODO: Look up some more behavior for I and B. Can't seem to find much
    // but some instructions DO set them.
    psw_i: bool,
    psw_b: bool,

    cycle_count: i32
}

impl<'a> Smp<'a> {
    pub fn new(emulator: &'a mut Apu) -> Smp<'a> {
        let mut ret = Smp {
            emulator: emulator,

            reg_pc: 0,
            reg_a: 0,
            reg_x: 0,
            reg_y: 0,
            reg_sp: 0,

            psw_c: false,
            psw_z: false,
            psw_h: false,
            psw_p: false,
            psw_v: false,
            psw_n: false,
            psw_i: false,
            psw_b: false,

            cycle_count: 0
        };
        ret.reset();
        ret
    }

    pub fn reset(&mut self) {
        self.reg_pc = 0xffc0;
        self.reg_a = 0;
        self.reg_x = 0;
        self.reg_y = 0;
        self.reg_sp = 0xef;
        self.set_psw(0x02);
    }

    pub fn set_reg_ya(&mut self, value: u16) {
        self.reg_a = (value & 0xff) as u8;
        self.reg_y = ((value >> 8) & 0xff) as u8;
    }

    pub fn get_reg_ya(&self) -> u16 {
        ((self.reg_y as u16) << 8) | (self.reg_a as u16)
    }

    pub fn set_psw(&mut self, value: u8) {
        self.psw_c = (value & 0x01) != 0;
        self.psw_z = (value & 0x02) != 0;
        self.psw_h = (value & 0x08) != 0;
        self.psw_p = (value & 0x20) != 0;
        self.psw_v = (value & 0x40) != 0;
        self.psw_n = (value & 0x80) != 0;
    }

    pub fn get_psw(&self) -> u8 {
        ((if self.psw_n { 1 } else { 0 }) << 7) |
        ((if self.psw_v { 1 } else { 0 }) << 6) |
        ((if self.psw_p { 1 } else { 0 }) << 5) |
        ((if self.psw_h { 1 } else { 0 }) << 3) |
        ((if self.psw_z { 1 } else { 0 }) << 1) |
        (if self.psw_c { 1 } else { 0 })
    }

    fn is_negative(value: u32) -> bool {
        (value & 0x80) != 0
    }

    fn cycles(&mut self, num_cycles: i32) {
        self.emulator.cpu_cycles_callback(num_cycles);
        self.cycle_count += num_cycles;
    }

    fn read_op(&mut self, addr: u16) -> u8 {
        self.cycles(1);
        self.emulator.read_byte(addr as u32)
    }

    fn write_op(&mut self, addr: u16, value: u8) {
        self.cycles(1);
        self.emulator.write_byte(addr as u32, value);
    }

    fn read_pc_op(&mut self) -> u8 {
        let addr = self.reg_pc;
        self.reg_pc += 1;
        let ret = self.read_op(addr);
        ret
    }

    fn read_sp_op(&mut self) -> u8 {
        self.reg_sp += 1;
        let addr = 0x0100 | (self.reg_sp as u16);
        self.read_op(addr)
    }

    fn write_sp_op(&mut self, value: u8) {
        let addr = 0x0100 | (self.reg_sp as u16);
        self.reg_sp -= 1;
        self.write_op(addr, value);
    }

    fn read_dp_op(&mut self, addr: u8) -> u8 {
        let addr = (if self.psw_p { 0x0100 } else { 0 }) | (addr as u16);
        self.read_op(addr)
    }

    fn write_dp_op(&mut self, addr: u8, value: u8) {
        let addr = (if self.psw_p { 0x0100 } else { 0 }) | (addr as u16);
        self.write_op(addr, value);
    }

    fn set_psw_n_z_op(&mut self, x: u32) {
        self.psw_n = Smp::is_negative(x);
        self.psw_z = x == 0;
    }

    fn adc_op(&mut self, x: u8, y: u8) -> u8 {
        let x = x as u32;
        let y = y as u32;
        let r = x + y + (if self.psw_c { 1 } else { 0 });
        self.psw_n = Smp::is_negative(r);
        self.psw_v = (!(x ^ y) & (x ^ r) & 0x80) != 0;
        self.psw_h = ((x ^ y ^ r) & 0x10) != 0;
        self.psw_z = (r & 0xff) == 0;
        self.psw_c = r > 0xff;
        (r & 0xff) as u8
    }

    fn and_op(&mut self, x: u8, y: u8) -> u8 {
        let ret = x & y;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn asl_op(&mut self, x: u8) -> u8 {
        self.psw_c = Smp::is_negative(x as u32);
        let ret = x << 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn cmp_op(&mut self, x: u8, y: u8) -> u8 {
        let r = (x as i32) - (y as i32);
        self.psw_n = (r & 0x80) != 0;
        self.psw_z = (r & 0xff) == 0;
        self.psw_c = r >= 0;
        x
    }

    fn dec_op(&mut self, x: u8) -> u8 {
        let ret = x - 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn eor_op(&mut self, x: u8, y: u8) -> u8 {
        let ret = x ^ y;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn inc_op(&mut self, x: u8) -> u8 {
        let ret = x + 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn ld_op(&mut self, _: u8, y: u8) -> u8 {
        self.set_psw_n_z_op(y as u32);
        y
    }

    fn lsr_op(&mut self, x: u8) -> u8 {
        self.psw_c = (x & 0x01) != 0;
        let ret = x >> 1;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn or_op(&mut self, x: u8, y: u8) -> u8 {
        let ret = x | y;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn rol_op(&mut self, x: u8) -> u8 {
        let carry = if self.psw_c { 1 } else { 0 };
        self.psw_c = (x & 0x80) != 0;
        let ret = (x << 1) | carry;
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn ror_op(&mut self, x: u8) -> u8 {
        let carry = if self.psw_c { 0x80 } else { 0 };
        self.psw_c = (x & 0x01) != 0;
        let ret = carry | (x >> 1);
        self.set_psw_n_z_op(ret as u32);
        ret
    }

    fn sbc_op(&mut self, x: u8, y: u8) -> u8 {
        self.adc_op(x, !y)
    }

    fn st_op(&self, _: u8, y: u8) -> u8 {
        y
    }

    fn adw_op(&mut self, x: u16, y: u16) -> u16 {
        self.psw_c = false;
        let mut ret = self.adc_op(x as u8, y as u8) as u16;
        ret |= (self.adc_op((x >> 8) as u8, (y >> 8) as u8) as u16) << 8;
        self.psw_z = ret == 0;
        ret
    }

    fn cpw_op(&mut self, x: u16, y: u16) -> u16 {
        let ret = (x as i32) - (y as i32);
        self.psw_n = (ret & 0x8000) != 0;
        self.psw_z = (ret as u16) == 0;
        self.psw_c = ret >= 0;
        ret as u16
    }

    fn ldw_op(&mut self, _: u16, y: u16) -> u16 {
        self.psw_n = (y & 0x8000) != 0;
        self.psw_z = y == 0;
        y
    }

    fn sbw_op(&mut self, x: u16, y: u16) -> u16 {
        self.psw_c = true;
        let mut ret = self.sbc_op(x as u8, y as u8) as u16;
        ret |= (self.sbc_op((x >> 8) as u8, (y >> 8) as u8) as u16) << 8;
        self.psw_z = ret == 0;
        ret
    }

    fn adjust_dpw_op(&mut self, x: u16) {
        let mut addr = self.read_pc_op();
        let mut result = (self.read_dp_op(addr) as u16) + x;
        self.write_dp_op(addr, result as u8);
        addr += 1;
        let mut high = (result >> 8) as u8;
        high += self.read_dp_op(addr);
        result = ((high as u16) << 8) | (result & 0xff);
        self.write_dp_op(addr, (result >> 8) as u8);
        self.psw_n = (result & 0x8000) != 0;
        self.psw_z = result == 0;
    }

    fn branch_op(&mut self, cond: bool) {
        let offset = self.read_pc_op();
        if !cond {
            return;
        }
        self.cycles(2);
        // TODO: Some of these casts might not be necessary; there's probably
        // a better way to add a i8 to a u16 with proper signs.
        self.reg_pc = ((self.reg_pc as i16) + ((offset as i8) as i16)) as u16;
    }

    fn branch_bit_op(&mut self, x: u8) {
        let addr = self.read_pc_op();
        let sp = self.read_dp_op(addr);
        let y = self.read_pc_op();
        self.cycles(1);
        if ((sp & (1 << (x >> 5))) != 0) == ((x & 0x10) != 0) {
            return;
        }
        self.cycles(2);
        // TODO: Some of these casts might not be necessary; there's probably
        // a better way to add a i8 to a u16 with proper signs.
        self.reg_pc = ((self.reg_pc as i16) + ((y as i8) as i16)) as u16;
    }

    fn pull_op(&mut self, x: &mut u8) {
        self.cycles(2);
        *x = self.read_sp_op();
    }

    fn push_op(&mut self, x: u8) {
        self.cycles(2);
        self.write_sp_op(x);
    }

    fn run(&mut self, target_cycles: i32) -> i32 {
        macro_rules! adjust_op {
            ($op:ident, $x:ident) => ({
                self.cycles(1);
                $x = self.$op($x);
            })
        }

        macro_rules! adjust_addr_op {
            ($op:ident) => ({
                let mut addr = self.read_pc_op() as u16;
                addr |= (self.read_pc_op() as u16) << 8;
                let mut result = self.read_op(addr);
                result = self.$op(result);
                self.write_op(addr, result);
            })
        }

        macro_rules! adjust_dp_op {
            ($op:ident) => ({
                let addr = self.read_pc_op() as u16;
                let mut result = self.read_dp_op(addr);
                result = self.$op(result);
                self.write_dp_op(addr, result);
            })
        }

        macro_rules! adjust_dp_x_op {
            ($op:ident) => ({
                let addr = self.read_pc_op();
                self.cycles(1);
                let mut result = self.read_dp_op(addr + self.reg_x);
                result = self.$op(result);
                self.write_dp_op(addr + self.reg_x, result);
            })
        }

        0 // TODO
    }
}
<|endoftext|>


<commit_before>macro_rules! def_store_number {
    ($m: ident, $t: ty) => {
        pub mod $m {
            use raft::state_machine::StateMachineCtl;
            use bifrost_hasher::hash_str;
            pub struct Number {
                pub num: $t,
                id: u64
            }
            raft_state_machine! {
                def cmd set(v: $t);
                def qry get() -> $t;

                def cmd get_and_add(n: $t) -> $t;
                def cmd add_and_get(n: $t) -> $t;

                def cmd get_and_minus(n: $t) -> $t;
                def cmd minus_and_get(n: $t) -> $t;

                def cmd get_and_incr(n: $t) -> $t;
                def cmd incr_and_get(n: $t) -> $t;

                def cmd get_and_decr(n: $t) -> $t;
                def cmd decr_and_get(n: $t) -> $t;

                def cmd get_and_multiply(n: $t) -> $t;
                def cmd multiply_and_get(n: $t) -> $t;

                def cmd get_and_divide(n: $t) -> $t;
                def cmd divide_and_get(n: $t) -> $t;
            }
            impl StateMachineCmds for Number {
                fn set(&mut self, n: $t) -> Result<(),()> {
                    self.num = n;
                    Ok(())
                }
                fn get(&self) -> Result<$t, ()> {
                    Ok(self.num)
                }
                fn get_and_add(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num += n;
                    Ok(on)
                }
                fn add_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num += n;
                    Ok(self.num)
                }
                fn get_and_minus(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num -= n;
                    Ok(on)
                }
                fn minus_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num -= n;
                    Ok(self.num)
                }
                fn get_and_incr(&mut self, n: $t) -> Result<$t, ()> {
                    self.get_and_add(1)
                }
                fn incr_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.add_and_get(1)
                }
                fn get_and_decr(&mut self, n: $t) -> Result<$t, ()> {
                    self.get_and_minus(1)
                }
                fn decr_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.minus_and_get(1)
                }
                fn get_and_multiply(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num *= n;
                    Ok(on)
                }
                fn multiply_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num *= n;
                    Ok(self.num)
                }
                fn get_and_divide(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num /= n;
                    Ok(on)
                }
                fn divide_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num /= n;
                    Ok(self.num)
                }
            }
            impl StateMachineCtl for Number {
                sm_complete!();
                fn snapshot(&self) -> Option<Vec<u8>> {
                    Some(serialize!(&self.num))
                }
                fn recover(&mut self, data: Vec<u8>) {
                    self.num = deserialize!(&data);
                }
                fn id(&self) -> u64 {self.id}
            }
            impl Number {
                pub fn new(id: u64, val: $t) -> Number {
                    Number {
                        num: val,
                        id: id,
                    }
                }
                pub fn new_by_name(name: String, num: $t) -> Number {
                    Number::new(hash_str(name), num)
                }
            }
        }
    };
}

def_store_number!(I8, i8);
def_store_number!(I16, i16);
def_store_number!(I32, i32);
def_store_number!(I64, i64);
def_store_number!(U8, u8);
def_store_number!(U16, u16);
def_store_number!(U32, u32);
def_store_number!(U64, u64);<commit_msg>floating point numbers<commit_after>macro_rules! def_store_number {
    ($m: ident, $t: ty) => {
        pub mod $m {
            use raft::state_machine::StateMachineCtl;
            use bifrost_hasher::hash_str;
            pub struct Number {
                pub num: $t,
                id: u64
            }
            raft_state_machine! {
                def cmd set(v: $t);
                def qry get() -> $t;

                def cmd get_and_add(n: $t) -> $t;
                def cmd add_and_get(n: $t) -> $t;

                def cmd get_and_minus(n: $t) -> $t;
                def cmd minus_and_get(n: $t) -> $t;

                def cmd get_and_incr(n: $t) -> $t;
                def cmd incr_and_get(n: $t) -> $t;

                def cmd get_and_decr(n: $t) -> $t;
                def cmd decr_and_get(n: $t) -> $t;

                def cmd get_and_multiply(n: $t) -> $t;
                def cmd multiply_and_get(n: $t) -> $t;

                def cmd get_and_divide(n: $t) -> $t;
                def cmd divide_and_get(n: $t) -> $t;
            }
            impl StateMachineCmds for Number {
                fn set(&mut self, n: $t) -> Result<(),()> {
                    self.num = n;
                    Ok(())
                }
                fn get(&self) -> Result<$t, ()> {
                    Ok(self.num)
                }
                fn get_and_add(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num += n;
                    Ok(on)
                }
                fn add_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num += n;
                    Ok(self.num)
                }
                fn get_and_minus(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num -= n;
                    Ok(on)
                }
                fn minus_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num -= n;
                    Ok(self.num)
                }
                fn get_and_incr(&mut self, n: $t) -> Result<$t, ()> {
                    self.get_and_add(1 as $t)
                }
                fn incr_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.add_and_get(1 as $t)
                }
                fn get_and_decr(&mut self, n: $t) -> Result<$t, ()> {
                    self.get_and_minus(1 as $t)
                }
                fn decr_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.minus_and_get(1 as $t)
                }
                fn get_and_multiply(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num *= n;
                    Ok(on)
                }
                fn multiply_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num *= n;
                    Ok(self.num)
                }
                fn get_and_divide(&mut self, n: $t) -> Result<$t, ()> {
                    let on = self.num;
                    self.num /= n;
                    Ok(on)
                }
                fn divide_and_get(&mut self, n: $t) -> Result<$t, ()> {
                    self.num /= n;
                    Ok(self.num)
                }
            }
            impl StateMachineCtl for Number {
                sm_complete!();
                fn snapshot(&self) -> Option<Vec<u8>> {
                    Some(serialize!(&self.num))
                }
                fn recover(&mut self, data: Vec<u8>) {
                    self.num = deserialize!(&data);
                }
                fn id(&self) -> u64 {self.id}
            }
            impl Number {
                pub fn new(id: u64, val: $t) -> Number {
                    Number {
                        num: val,
                        id: id,
                    }
                }
                pub fn new_by_name(name: String, num: $t) -> Number {
                    Number::new(hash_str(name), num)
                }
            }
        }
    };
}

def_store_number!(I8, i8);
def_store_number!(I16, i16);
def_store_number!(I32, i32);
def_store_number!(I64, i64);
def_store_number!(U8, u8);
def_store_number!(U16, u16);
def_store_number!(U32, u32);
def_store_number!(U64, u64);
def_store_number!(F64, f64);
def_store_number!(F32, f32);<|endoftext|>