<commit_before>#![crate_name = "sam4l"]
#![crate_type = "rlib"]
#![feature(asm,core_intrinsics,concat_idents,const_fn, clone_from_slice)]
#![no_std]

#[macro_use]
extern crate common;
extern crate cortexm4;
extern crate hil;
extern crate process;

#[macro_use]
mod helpers;

pub mod chip;
pub mod ast;
pub mod bpm;
pub mod dma;
pub mod i2c;
pub mod spi;
pub mod nvic;
pub mod pm;
pub mod gpio;
pub mod usart;
pub mod scif;
pub mod adc;
pub mod flashcalw;

unsafe extern "C" fn unhandled_interrupt() {
    let mut interrupt_number: u32;

    // IPSR[8:0] holds the currently active interrupt
    asm!(
        "mrs    r0, ipsr                    "
        : "={r0}"(interrupt_number)
        :
        : "r0"
        :
        );

    interrupt_number = interrupt_number & 0x1ff;

    panic!("Unhandled Interrupt. ISR {} is active.", interrupt_number);
}

extern {
    // _estack is not really a function, but it makes the types work
    // You should never actually invoke it!!
    fn _estack();

    // Defined in src/main/main.rs
    fn main();

    // Defined in src/arch/cortex-m4/ctx_switch.S
    fn SVC_Handler();
    fn systick_handler();

    fn generic_isr();

    static mut _szero : u32;
    static mut _ezero : u32;
    static mut _etext : u32;
    static mut _srelocate : u32;
    static mut _erelocate : u32;
}

#[link_section=".vectors"]
#[no_mangle] // Ensures that the symbol is kept until the final binary
pub static BASE_VECTORS: [unsafe extern fn(); 16] = [
    _estack, reset_handler,
    /* NMI */           unhandled_interrupt,
    /* Hard Fault */    hard_fault_handler,
    /* MemManage */     unhandled_interrupt,
    /* BusFault */      unhandled_interrupt,
    /* UsageFault*/     unhandled_interrupt,
    unhandled_interrupt, unhandled_interrupt, unhandled_interrupt,
    unhandled_interrupt,
    /* SVC */           SVC_Handler,
    /* DebugMon */      unhandled_interrupt,
    unhandled_interrupt,
    /* PendSV */        unhandled_interrupt,
    /* SysTick */       systick_handler
];

#[link_section=".vectors"]
#[no_mangle] // Ensures that the symbol is kept until the final binary
pub static IRQS: [unsafe extern fn(); 80] = [generic_isr; 80];

#[no_mangle]
pub static INTERRUPT_TABLE: [Option<unsafe extern fn()>; 80] = [
    // Perhipheral vectors are defined by Atmel in the SAM4L datasheet section
    // 4.7.
    /* HFLASHC */       Option::Some(flashcalw::flash_handler),
    /* PDCA0 */         Option::Some(dma::pdca0_handler),
    /* PDCA1 */         Option::Some(dma::pdca1_handler),
    /* PDCA2 */         Option::Some(dma::pdca2_handler),
    /* PDCA3 */         Option::Some(dma::pdca3_handler),
    /* PDCA4 */         Option::Some(dma::pdca4_handler),
    /* PDCA5 */         Option::Some(dma::pdca5_handler),
    /* PDCA6 */         Option::Some(dma::pdca6_handler),
    /* PDCA7 */         Option::Some(dma::pdca7_handler),
    /* PDCA8 */         Option::Some(dma::pdca8_handler),
    /* PDCA9 */         Option::Some(dma::pdca9_handler),
    /* PDCA10 */        Option::Some(dma::pdca10_handler),
    /* PDCA11 */        Option::Some(dma::pdca11_handler),
    /* PDCA12 */        Option::Some(dma::pdca12_handler),
    /* PDCA13 */        Option::Some(dma::pdca13_handler),
    /* PDCA14 */        Option::Some(dma::pdca14_handler),
    /* PDCA15 */        Option::Some(dma::pdca15_handler),
    /* CRCCU */         Option::Some(unhandled_interrupt),
    /* USBC */          Option::Some(unhandled_interrupt),
    /* PEVC_TR */       Option::Some(unhandled_interrupt),
    /* PEVC_OV */       Option::Some(unhandled_interrupt),
    /* AESA */          Option::Some(unhandled_interrupt),
    /* PM */            Option::Some(unhandled_interrupt),
    /* SCIF */          Option::Some(unhandled_interrupt),
    /* FREQM */         Option::Some(unhandled_interrupt),
    /* GPIO0 */         Option::Some(gpio::gpio0_handler),
    /* GPIO1 */         Option::Some(gpio::gpio1_handler),
    /* GPIO2 */         Option::Some(gpio::gpio2_handler),
    /* GPIO3 */         Option::Some(gpio::gpio3_handler),
    /* GPIO4 */         Option::Some(gpio::gpio4_handler),
    /* GPIO5 */         Option::Some(gpio::gpio5_handler),
    /* GPIO6 */         Option::Some(gpio::gpio6_handler),
    /* GPIO7 */         Option::Some(gpio::gpio7_handler),
    /* GPIO8 */         Option::Some(gpio::gpio8_handler),
    /* GPIO9 */         Option::Some(gpio::gpio9_handler),
    /* GPIO10 */        Option::Some(gpio::gpio10_handler),
    /* GPIO11 */        Option::Some(gpio::gpio11_handler),
    /* BPM */           Option::Some(unhandled_interrupt),
    /* BSCIF */         Option::Some(unhandled_interrupt),
    /* AST_ALARM */     Option::Some(ast::ast_alarm_handler),
    /* AST_PER */       Option::Some(unhandled_interrupt),
    /* AST_OVF */       Option::Some(unhandled_interrupt),
    /* AST_READY */     Option::Some(unhandled_interrupt),
    /* AST_CLKREADY */  Option::Some(unhandled_interrupt),
    /* WDT */           Option::Some(unhandled_interrupt),
    /* EIC1 */          Option::Some(unhandled_interrupt),
    /* EIC2 */          Option::Some(unhandled_interrupt),
    /* EIC3 */          Option::Some(unhandled_interrupt),
    /* EIC4 */          Option::Some(unhandled_interrupt),
    /* EIC5 */          Option::Some(unhandled_interrupt),
    /* EIC6 */          Option::Some(unhandled_interrupt),
    /* EIC7 */          Option::Some(unhandled_interrupt),
    /* EIC8 */          Option::Some(unhandled_interrupt),
    /* IISC */          Option::Some(unhandled_interrupt),
    /* SPI */           Option::Some(unhandled_interrupt),
    /* TC00 */          Option::Some(unhandled_interrupt),
    /* TC01 */          Option::Some(unhandled_interrupt),
    /* TC02 */          Option::Some(unhandled_interrupt),
    /* TC10 */          Option::Some(unhandled_interrupt),
    /* TC11 */          Option::Some(unhandled_interrupt),
    /* TC12 */          Option::Some(unhandled_interrupt),
    /* TWIM0 */         Option::Some(i2c::twim0_handler),
    /* TWIS0 */         Option::Some(unhandled_interrupt),
    /* TWIM1 */         Option::Some(i2c::twim1_handler),
    /* TWIS1 */         Option::Some(unhandled_interrupt),
    /* USART0 */        Option::Some(usart::usart0_handler),
    /* USART1 */        Option::Some(usart::usart1_handler),
    /* USART2 */        Option::Some(usart::usart2_handler),
    /* USART3 */        Option::Some(usart::usart3_handler),
    /* ADCIFE */        Option::Some(adc::adcife_handler),
    /* DACC */          Option::Some(unhandled_interrupt),
    /* ACIFC */         Option::Some(unhandled_interrupt),
    /* ABDACB */        Option::Some(unhandled_interrupt),
    /* TRNG */          Option::Some(unhandled_interrupt),
    /* PARC */          Option::Some(unhandled_interrupt),
    /* CATB */          Option::Some(unhandled_interrupt),
    None,
    /* TWIM2 */         Option::Some(i2c::twim2_handler),
    /* TWIM3 */         Option::Some(i2c::twim3_handler),
    /* LCDCA */         Option::Some(unhandled_interrupt),
];

unsafe extern "C" fn reset_handler() {

    // Relocate data segment.
    // Assumes data starts right after text segment as specified by the linker
    // file.
    let mut pdest  = &mut _srelocate as *mut u32;
    let pend  = &mut _erelocate as *mut u32;
    let mut psrc = &_etext as *const u32;

    if psrc != pdest {
        while (pdest as *const u32) < pend {
            *pdest = *psrc;
            pdest = pdest.offset(1);
            psrc = psrc.offset(1);
        }
    }

    // Clear the zero segment (BSS)
    let pzero = &_ezero as *const u32;
    pdest = &mut _szero as *mut u32;

    while (pdest as *const u32) < pzero {
        *pdest = 0;
        pdest = pdest.offset(1);
    }

    main();
}

unsafe extern "C" fn hard_fault_handler() {
    use core::intrinsics::offset;

    let faulting_stack: *mut u32;
    let kernel_stack: bool;

    asm!(
        "mov    r1, 0                       \n\
         tst    lr, #4                      \n\
         itte   eq                          \n\
         mrseq  r0, msp                     \n\
         addeq  r1, 1                       \n\
         mrsne  r0, psp                     "
        : "={r0}"(faulting_stack), "={r1}"(kernel_stack)
        :
        : "r0", "r1"
        :
        );

    let stacked_r0  :u32 = *offset(faulting_stack, 0);
    let stacked_r1  :u32 = *offset(faulting_stack, 1);
    let stacked_r2  :u32 = *offset(faulting_stack, 2);
    let stacked_r3  :u32 = *offset(faulting_stack, 3);
    let stacked_r12 :u32 = *offset(faulting_stack, 4);
    let stacked_lr  :u32 = *offset(faulting_stack, 5);
    let stacked_pc  :u32 = *offset(faulting_stack, 6);
    let stacked_prs :u32 = *offset(faulting_stack, 7);

    let mode_str = if kernel_stack { "Kernel" } else { "Process" };

    let shcsr : u32 = core::intrinsics::volatile_load(0xE000ED24 as *const u32);
    let cfsr : u32 = core::intrinsics::volatile_load(0xE000ED28 as *const u32);
    let hfsr : u32 = core::intrinsics::volatile_load(0xE000ED2C as *const u32);

    panic!("{} HardFault.\n\
           \tr0  0x{:x}\n\
           \tr1  0x{:x}\n\
           \tr2  0x{:x}\n\
           \tr3  0x{:x}\n\
           \tr12 0x{:x}\n\
           \tlr  0x{:x}\n\
           \tpc  0x{:x}\n\
           \tprs 0x{:x}\n\
           \tsp  0x{:x}\n\
           \tSHCSR 0x{:x}\n\
           \tCFSR  0x{:x}\n\
           \tHSFR  0x{:x}\n\
           ", mode_str,
           stacked_r0, stacked_r1, stacked_r2, stacked_r3,
           stacked_r12, stacked_lr, stacked_pc, stacked_prs,
           faulting_stack as u32, shcsr, cfsr, hfsr);
}

<commit_msg>cleanup compiler warning<commit_after>#![crate_name = "sam4l"]
#![crate_type = "rlib"]
#![feature(asm,core_intrinsics,concat_idents,const_fn)]
#![no_std]

#[macro_use]
extern crate common;
extern crate cortexm4;
extern crate hil;
extern crate process;

#[macro_use]
mod helpers;

pub mod chip;
pub mod ast;
pub mod bpm;
pub mod dma;
pub mod i2c;
pub mod spi;
pub mod nvic;
pub mod pm;
pub mod gpio;
pub mod usart;
pub mod scif;
pub mod adc;
pub mod flashcalw;

unsafe extern "C" fn unhandled_interrupt() {
    let mut interrupt_number: u32;

    // IPSR[8:0] holds the currently active interrupt
    asm!(
        "mrs    r0, ipsr                    "
        : "={r0}"(interrupt_number)
        :
        : "r0"
        :
        );

    interrupt_number = interrupt_number & 0x1ff;

    panic!("Unhandled Interrupt. ISR {} is active.", interrupt_number);
}

extern {
    // _estack is not really a function, but it makes the types work
    // You should never actually invoke it!!
    fn _estack();

    // Defined in src/main/main.rs
    fn main();

    // Defined in src/arch/cortex-m4/ctx_switch.S
    fn SVC_Handler();
    fn systick_handler();

    fn generic_isr();

    static mut _szero : u32;
    static mut _ezero : u32;
    static mut _etext : u32;
    static mut _srelocate : u32;
    static mut _erelocate : u32;
}

#[link_section=".vectors"]
#[no_mangle] // Ensures that the symbol is kept until the final binary
pub static BASE_VECTORS: [unsafe extern fn(); 16] = [
    _estack, reset_handler,
    /* NMI */           unhandled_interrupt,
    /* Hard Fault */    hard_fault_handler,
    /* MemManage */     unhandled_interrupt,
    /* BusFault */      unhandled_interrupt,
    /* UsageFault*/     unhandled_interrupt,
    unhandled_interrupt, unhandled_interrupt, unhandled_interrupt,
    unhandled_interrupt,
    /* SVC */           SVC_Handler,
    /* DebugMon */      unhandled_interrupt,
    unhandled_interrupt,
    /* PendSV */        unhandled_interrupt,
    /* SysTick */       systick_handler
];

#[link_section=".vectors"]
#[no_mangle] // Ensures that the symbol is kept until the final binary
pub static IRQS: [unsafe extern fn(); 80] = [generic_isr; 80];

#[no_mangle]
pub static INTERRUPT_TABLE: [Option<unsafe extern fn()>; 80] = [
    // Perhipheral vectors are defined by Atmel in the SAM4L datasheet section
    // 4.7.
    /* HFLASHC */       Option::Some(flashcalw::flash_handler),
    /* PDCA0 */         Option::Some(dma::pdca0_handler),
    /* PDCA1 */         Option::Some(dma::pdca1_handler),
    /* PDCA2 */         Option::Some(dma::pdca2_handler),
    /* PDCA3 */         Option::Some(dma::pdca3_handler),
    /* PDCA4 */         Option::Some(dma::pdca4_handler),
    /* PDCA5 */         Option::Some(dma::pdca5_handler),
    /* PDCA6 */         Option::Some(dma::pdca6_handler),
    /* PDCA7 */         Option::Some(dma::pdca7_handler),
    /* PDCA8 */         Option::Some(dma::pdca8_handler),
    /* PDCA9 */         Option::Some(dma::pdca9_handler),
    /* PDCA10 */        Option::Some(dma::pdca10_handler),
    /* PDCA11 */        Option::Some(dma::pdca11_handler),
    /* PDCA12 */        Option::Some(dma::pdca12_handler),
    /* PDCA13 */        Option::Some(dma::pdca13_handler),
    /* PDCA14 */        Option::Some(dma::pdca14_handler),
    /* PDCA15 */        Option::Some(dma::pdca15_handler),
    /* CRCCU */         Option::Some(unhandled_interrupt),
    /* USBC */          Option::Some(unhandled_interrupt),
    /* PEVC_TR */       Option::Some(unhandled_interrupt),
    /* PEVC_OV */       Option::Some(unhandled_interrupt),
    /* AESA */          Option::Some(unhandled_interrupt),
    /* PM */            Option::Some(unhandled_interrupt),
    /* SCIF */          Option::Some(unhandled_interrupt),
    /* FREQM */         Option::Some(unhandled_interrupt),
    /* GPIO0 */         Option::Some(gpio::gpio0_handler),
    /* GPIO1 */         Option::Some(gpio::gpio1_handler),
    /* GPIO2 */         Option::Some(gpio::gpio2_handler),
    /* GPIO3 */         Option::Some(gpio::gpio3_handler),
    /* GPIO4 */         Option::Some(gpio::gpio4_handler),
    /* GPIO5 */         Option::Some(gpio::gpio5_handler),
    /* GPIO6 */         Option::Some(gpio::gpio6_handler),
    /* GPIO7 */         Option::Some(gpio::gpio7_handler),
    /* GPIO8 */         Option::Some(gpio::gpio8_handler),
    /* GPIO9 */         Option::Some(gpio::gpio9_handler),
    /* GPIO10 */        Option::Some(gpio::gpio10_handler),
    /* GPIO11 */        Option::Some(gpio::gpio11_handler),
    /* BPM */           Option::Some(unhandled_interrupt),
    /* BSCIF */         Option::Some(unhandled_interrupt),
    /* AST_ALARM */     Option::Some(ast::ast_alarm_handler),
    /* AST_PER */       Option::Some(unhandled_interrupt),
    /* AST_OVF */       Option::Some(unhandled_interrupt),
    /* AST_READY */     Option::Some(unhandled_interrupt),
    /* AST_CLKREADY */  Option::Some(unhandled_interrupt),
    /* WDT */           Option::Some(unhandled_interrupt),
    /* EIC1 */          Option::Some(unhandled_interrupt),
    /* EIC2 */          Option::Some(unhandled_interrupt),
    /* EIC3 */          Option::Some(unhandled_interrupt),
    /* EIC4 */          Option::Some(unhandled_interrupt),
    /* EIC5 */          Option::Some(unhandled_interrupt),
    /* EIC6 */          Option::Some(unhandled_interrupt),
    /* EIC7 */          Option::Some(unhandled_interrupt),
    /* EIC8 */          Option::Some(unhandled_interrupt),
    /* IISC */          Option::Some(unhandled_interrupt),
    /* SPI */           Option::Some(unhandled_interrupt),
    /* TC00 */          Option::Some(unhandled_interrupt),
    /* TC01 */          Option::Some(unhandled_interrupt),
    /* TC02 */          Option::Some(unhandled_interrupt),
    /* TC10 */          Option::Some(unhandled_interrupt),
    /* TC11 */          Option::Some(unhandled_interrupt),
    /* TC12 */          Option::Some(unhandled_interrupt),
    /* TWIM0 */         Option::Some(i2c::twim0_handler),
    /* TWIS0 */         Option::Some(unhandled_interrupt),
    /* TWIM1 */         Option::Some(i2c::twim1_handler),
    /* TWIS1 */         Option::Some(unhandled_interrupt),
    /* USART0 */        Option::Some(usart::usart0_handler),
    /* USART1 */        Option::Some(usart::usart1_handler),
    /* USART2 */        Option::Some(usart::usart2_handler),
    /* USART3 */        Option::Some(usart::usart3_handler),
    /* ADCIFE */        Option::Some(adc::adcife_handler),
    /* DACC */          Option::Some(unhandled_interrupt),
    /* ACIFC */         Option::Some(unhandled_interrupt),
    /* ABDACB */        Option::Some(unhandled_interrupt),
    /* TRNG */          Option::Some(unhandled_interrupt),
    /* PARC */          Option::Some(unhandled_interrupt),
    /* CATB */          Option::Some(unhandled_interrupt),
    None,
    /* TWIM2 */         Option::Some(i2c::twim2_handler),
    /* TWIM3 */         Option::Some(i2c::twim3_handler),
    /* LCDCA */         Option::Some(unhandled_interrupt),
];

unsafe extern "C" fn reset_handler() {

    // Relocate data segment.
    // Assumes data starts right after text segment as specified by the linker
    // file.
    let mut pdest  = &mut _srelocate as *mut u32;
    let pend  = &mut _erelocate as *mut u32;
    let mut psrc = &_etext as *const u32;

    if psrc != pdest {
        while (pdest as *const u32) < pend {
            *pdest = *psrc;
            pdest = pdest.offset(1);
            psrc = psrc.offset(1);
        }
    }

    // Clear the zero segment (BSS)
    let pzero = &_ezero as *const u32;
    pdest = &mut _szero as *mut u32;

    while (pdest as *const u32) < pzero {
        *pdest = 0;
        pdest = pdest.offset(1);
    }

    main();
}

unsafe extern "C" fn hard_fault_handler() {
    use core::intrinsics::offset;

    let faulting_stack: *mut u32;
    let kernel_stack: bool;

    asm!(
        "mov    r1, 0                       \n\
         tst    lr, #4                      \n\
         itte   eq                          \n\
         mrseq  r0, msp                     \n\
         addeq  r1, 1                       \n\
         mrsne  r0, psp                     "
        : "={r0}"(faulting_stack), "={r1}"(kernel_stack)
        :
        : "r0", "r1"
        :
        );

    let stacked_r0  :u32 = *offset(faulting_stack, 0);
    let stacked_r1  :u32 = *offset(faulting_stack, 1);
    let stacked_r2  :u32 = *offset(faulting_stack, 2);
    let stacked_r3  :u32 = *offset(faulting_stack, 3);
    let stacked_r12 :u32 = *offset(faulting_stack, 4);
    let stacked_lr  :u32 = *offset(faulting_stack, 5);
    let stacked_pc  :u32 = *offset(faulting_stack, 6);
    let stacked_prs :u32 = *offset(faulting_stack, 7);

    let mode_str = if kernel_stack { "Kernel" } else { "Process" };

    let shcsr : u32 = core::intrinsics::volatile_load(0xE000ED24 as *const u32);
    let cfsr : u32 = core::intrinsics::volatile_load(0xE000ED28 as *const u32);
    let hfsr : u32 = core::intrinsics::volatile_load(0xE000ED2C as *const u32);

    panic!("{} HardFault.\n\
           \tr0  0x{:x}\n\
           \tr1  0x{:x}\n\
           \tr2  0x{:x}\n\
           \tr3  0x{:x}\n\
           \tr12 0x{:x}\n\
           \tlr  0x{:x}\n\
           \tpc  0x{:x}\n\
           \tprs 0x{:x}\n\
           \tsp  0x{:x}\n\
           \tSHCSR 0x{:x}\n\
           \tCFSR  0x{:x}\n\
           \tHSFR  0x{:x}\n\
           ", mode_str,
           stacked_r0, stacked_r1, stacked_r2, stacked_r3,
           stacked_r12, stacked_lr, stacked_pc, stacked_prs,
           faulting_stack as u32, shcsr, cfsr, hfsr);
}

<|endoftext|>


<commit_before>use crate::backend::Backend;
use crate::expression::TypedExpressionType;
use crate::expression::*;
use crate::query_builder::*;
use crate::query_source::joins::ToInnerJoin;
use crate::result::QueryResult;
use crate::sql_types::{DieselNumericOps, IntoNullable};

#[derive(Debug, Copy, Clone, DieselNumericOps, ValidGrouping)]
pub struct Nullable<T>(T);

impl<T> Nullable<T> {
    pub fn new(expr: T) -> Self {
        Nullable(expr)
    }
}

impl<T> Expression for Nullable<T>
where
    T: Expression,
    T::SqlType: IntoNullable,
    <T::SqlType as IntoNullable>::Nullable: TypedExpressionType,
{
    type SqlType = <T::SqlType as IntoNullable>::Nullable;
}

impl<T, DB> QueryFragment<DB> for Nullable<T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
        self.0.walk_ast(pass)
    }
}

/// Nullable can be used in where clauses everywhere, but can only be used in
/// select clauses for outer joins.
impl<T, QS> AppearsOnTable<QS> for Nullable<T>
where
    T: AppearsOnTable<QS>,
    Nullable<T>: Expression,
{
}

impl<T: QueryId> QueryId for Nullable<T> {
    type QueryId = T::QueryId;

    const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID;
}

impl<T, DB> Selectable<DB> for Option<T>
where
    DB: Backend,
    T: Selectable<DB>,
    Nullable<T::SelectExpression>: Expression,
{
    type SelectExpression = Nullable<T::SelectExpression>;

    fn construct_selection() -> Self::SelectExpression {
        Nullable::new(T::construct_selection())
    }
}

impl<T, QS> SelectableExpression<QS> for Nullable<T>
where
    Self: AppearsOnTable<QS>,
    QS: ToInnerJoin,
    T: SelectableExpression<QS::InnerJoin>,
{
}

impl<T> SelectableExpression<()> for Nullable<T> where Self: AppearsOnTable<()> {}
<commit_msg>remove untrue comment<commit_after>use crate::backend::Backend;
use crate::expression::TypedExpressionType;
use crate::expression::*;
use crate::query_builder::*;
use crate::query_source::joins::ToInnerJoin;
use crate::result::QueryResult;
use crate::sql_types::{DieselNumericOps, IntoNullable};

#[derive(Debug, Copy, Clone, DieselNumericOps, ValidGrouping)]
pub struct Nullable<T>(T);

impl<T> Nullable<T> {
    pub fn new(expr: T) -> Self {
        Nullable(expr)
    }
}

impl<T> Expression for Nullable<T>
where
    T: Expression,
    T::SqlType: IntoNullable,
    <T::SqlType as IntoNullable>::Nullable: TypedExpressionType,
{
    type SqlType = <T::SqlType as IntoNullable>::Nullable;
}

impl<T, DB> QueryFragment<DB> for Nullable<T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
        self.0.walk_ast(pass)
    }
}

impl<T, QS> AppearsOnTable<QS> for Nullable<T>
where
    T: AppearsOnTable<QS>,
    Nullable<T>: Expression,
{
}

impl<T: QueryId> QueryId for Nullable<T> {
    type QueryId = T::QueryId;

    const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID;
}

impl<T, DB> Selectable<DB> for Option<T>
where
    DB: Backend,
    T: Selectable<DB>,
    Nullable<T::SelectExpression>: Expression,
{
    type SelectExpression = Nullable<T::SelectExpression>;

    fn construct_selection() -> Self::SelectExpression {
        Nullable::new(T::construct_selection())
    }
}

impl<T, QS> SelectableExpression<QS> for Nullable<T>
where
    Self: AppearsOnTable<QS>,
    QS: ToInnerJoin,
    T: SelectableExpression<QS::InnerJoin>,
{
}

impl<T> SelectableExpression<()> for Nullable<T> where Self: AppearsOnTable<()> {}
<|endoftext|>


<commit_before>/// Implements the [`Identifiable`][identifiable] trait for a reference to a
/// given struct. This macro should be called by copy/pasting the definition of
/// the struct into it.
///
/// The struct must have a field called `id`, and the type of that field must be
/// `Copy`. This macro does not work with tuple structs.
///
/// [identifiable]: /diesel/associations/trait.Identifiable.html
///
/// # Example
///
/// ```no_run
/// # #[macro_use] extern crate diesel;
/// # table! { users { id -> Integer, } }
/// struct User {
///     id: i32,
///     name: String,
/// }
///
/// impl_Identifiable! {
///     #[table_name(users)]
///     struct User {
///         id: i32,
///         name: String,
///     }
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! impl_Identifiable {
    // Find table name in options
    (
        $(())*
        $(#[$option_name:ident $option_value:tt])*
        $(pub)* struct $($rest:tt)*
    ) => {
        __diesel_find_option_with_name! {
            (options = [$(#[$option_name $option_value])*], body = $($rest)*),
            option_name = table_name,
            args = [$(#[$option_name $option_value])*],
            callback = impl_Identifiable,
        }
    };

    // Next, find primary key name in options
    (
        (options = $options:tt, $($args:tt)*),
        found_option_with_name = table_name,
        value = ($table_name:ident),
    ) => {
        __diesel_find_option_with_name! {
            (options = $options, table_name = $table_name, $($args)*),
            option_name = primary_key,
            args = $options,
            callback = impl_Identifiable,
            default = (id),
        }
    };

    // Options extracted, deal with the struct body (bottom two branches)
    (
        (
            options = $ignore:tt,
            table_name = $table_name:ident,
            body = $($body:tt)*
        ),
        found_option_with_name = primary_key,
        value = $primary_key_names:tt,
    ) => {
        impl_Identifiable! {
            (
                table_name = $table_name,
                primary_key_names = $primary_key_names,
            )
            $($body)*
        }
    };

    // We found the primary key field, return the final impl
    (
        (
            table_name = $table_name:ident,
            struct_ty = $struct_ty:ty,
            lifetimes = ($($lifetimes:tt),*),
        ),
        found_fields_with_field_names,
        fields = [$({
            field_name: $field_name:ident,
            column_name: $column_name:ident,
            field_ty: $field_ty:ty,
            field_kind: $field_kind:ident,
            $($rest:tt)*
        })*],
    ) => {
        impl<$($lifetimes),*> $crate::associations::HasTable for $struct_ty {
            type Table = $table_name::table;

            fn table() -> Self::Table {
                $table_name::table
            }
        }

        impl<'ident $(,$lifetimes)*> $crate::associations::Identifiable for &'ident $struct_ty {
            type Id = ($(&'ident $field_ty),*);

            fn id(self) -> Self::Id {
                ($(&self.$field_name),*)
            }
        }
    };

    // Search for the primary key fields and continue
    (
        (
            table_name = $table_name:ident,
            primary_key_names = $primary_key_names:tt,
            $($args:tt)*
        ),
        fields = $fields:tt,
    ) => {
        __diesel_fields_with_field_names! {
            (table_name = $table_name, $($args)*),
            callback = impl_Identifiable,
            targets = $primary_key_names,
            fields = $fields,
        }
    };

    // Handle struct with generic lifetimes
    (
        ($($args:tt)*)
        $struct_name:ident <$($lifetimes:tt),*>
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                $($args)*
                struct_ty = $struct_name<$($lifetimes),*>,
                lifetimes = ($($lifetimes),*),
            ),
            callback = impl_Identifiable,
            body = $body,
        }
    };

    // Handle struct with no generics
    (
        ($($args:tt)*)
        $struct_name:ident
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                $($args)*
                struct_ty = $struct_name,
                lifetimes = (),
            ),
            callback = impl_Identifiable,
            body = $body,
        }
    };
}

table! {
    foos {
        id -> Integer,
    }
}

table! {
    bars {
        id -> VarChar,
    }
}

#[test]
fn derive_identifiable_on_simple_struct() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations)]
    struct Foo {
        id: i32,
        #[allow(dead_code)]
        foo: i32,
    }

    impl_Identifiable! {
        #[table_name(foos)]
        struct Foo {
            id: i32,
            foo: i32,
        }
    }

    let foo1 = Foo { id: 1, foo: 2 };
    let foo2 = Foo { id: 2, foo: 3 };
    assert_eq!(&1, foo1.id());
    assert_eq!(&2, foo2.id());
}

#[test]
fn derive_identifiable_when_id_is_not_first_field() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations)]
    struct Foo {
        #[allow(dead_code)]
        foo: i32,
        id: i32,
    }

    impl_Identifiable! {
        #[table_name(foos)]
        struct Foo {
            foo: i32,
            id: i32,
        }
    }

    let foo1 = Foo { id: 1, foo: 2 };
    let foo2 = Foo { id: 2, foo: 3 };
    assert_eq!(&1, foo1.id());
    assert_eq!(&2, foo2.id());
}

#[test]
fn derive_identifiable_on_struct_with_non_integer_pk() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations)]
    struct Foo {
        id: &'static str,
        #[allow(dead_code)]
        foo: i32,
    }

    impl_Identifiable! {
        #[table_name(bars)]
        struct Foo {
            id: &'static str,
            foo: i32,
        }
    }

    let foo1 = Foo { id: "hi", foo: 2 };
    let foo2 = Foo { id: "there", foo: 3 };
    assert_eq!(&"hi", foo1.id());
    assert_eq!(&"there", foo2.id());
}

#[test]
fn derive_identifiable_on_struct_with_lifetime() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations)]
    struct Foo<'a> {
        id: &'a str,
        #[allow(dead_code)]
        foo: i32,
    }

    impl_Identifiable! {
        #[table_name(bars)]
        struct Foo<'a> {
            id: &'a str,
            foo: i32,
        }
    }

    let foo1 = Foo { id: "hi", foo: 2 };
    let foo2 = Foo { id: "there", foo: 3 };
    assert_eq!(&"hi", foo1.id());
    assert_eq!(&"there", foo2.id());
}

#[test]
fn derive_identifiable_with_non_standard_pk() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations, dead_code)]
    struct Foo<'a> {
        id: i32,
        foo_id: &'a str,
        foo: i32,
    }

    impl_Identifiable! {
        #[table_name(bars)]
        #[primary_key(foo_id)]
        struct Foo<'a> {
            id: i32,
            foo_id: &'a str,
            foo: i32,
        }
    }

    let foo1 = Foo { id: 1, foo_id: "hi", foo: 2 };
    let foo2 = Foo { id: 2, foo_id: "there", foo: 3 };
    assert_eq!(&"hi", foo1.id());
    assert_eq!(&"there", foo2.id());
}

#[test]
fn derive_identifiable_with_non_standard_pk_given_before_table_name() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations, dead_code)]
    struct Foo<'a> {
        id: i32,
        foo_id: &'a str,
        foo: i32,
    }

    impl_Identifiable! {
        #[primary_key(foo_id)]
        #[table_name(bars)]
        struct Foo<'a> {
            id: i32,
            foo_id: &'a str,
            foo: i32,
        }
    }

    let foo1 = Foo { id: 1, foo_id: "hi", foo: 2 };
    let foo2 = Foo { id: 2, foo_id: "there", foo: 3 };
    assert_eq!(&"hi", foo1.id());
    assert_eq!(&"there", foo2.id());
}

#[test]
fn derive_identifiable_with_composite_pk() {
    use associations::Identifiable;

    #[allow(missing_debug_implementations, missing_copy_implementations, dead_code)]
    struct Foo {
        id: i32,
        foo_id: i32,
        bar_id: i32,
        foo: i32,
    }

    impl_Identifiable! {
        #[primary_key(foo_id, bar_id)]
        #[table_name(bars)]
        struct Foo {
            id: i32,
            foo_id: i32,
            bar_id: i32,
            foo: i32,
        }
    }

    let foo1 = Foo { id: 1, foo_id: 2, bar_id: 3, foo: 4 };
    let foo2 = Foo { id: 5, foo_id: 6, bar_id: 7, foo: 8 };
    assert_eq!((&2, &3), foo1.id());
    assert_eq!((&6, &7), foo2.id());
}
<commit_msg>Put impl_Identifiable! tests in test module<commit_after>/// Implements the [`Identifiable`][identifiable] trait for a reference to a
/// given struct. This macro should be called by copy/pasting the definition of
/// the struct into it.
///
/// The struct must have a field called `id`, and the type of that field must be
/// `Copy`. This macro does not work with tuple structs.
///
/// [identifiable]: /diesel/associations/trait.Identifiable.html
///
/// # Example
///
/// ```no_run
/// # #[macro_use] extern crate diesel;
/// # table! { users { id -> Integer, } }
/// struct User {
///     id: i32,
///     name: String,
/// }
///
/// impl_Identifiable! {
///     #[table_name(users)]
///     struct User {
///         id: i32,
///         name: String,
///     }
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! impl_Identifiable {
    // Find table name in options
    (
        $(())*
        $(#[$option_name:ident $option_value:tt])*
        $(pub)* struct $($rest:tt)*
    ) => {
        __diesel_find_option_with_name! {
            (options = [$(#[$option_name $option_value])*], body = $($rest)*),
            option_name = table_name,
            args = [$(#[$option_name $option_value])*],
            callback = impl_Identifiable,
        }
    };

    // Next, find primary key name in options
    (
        (options = $options:tt, $($args:tt)*),
        found_option_with_name = table_name,
        value = ($table_name:ident),
    ) => {
        __diesel_find_option_with_name! {
            (options = $options, table_name = $table_name, $($args)*),
            option_name = primary_key,
            args = $options,
            callback = impl_Identifiable,
            default = (id),
        }
    };

    // Options extracted, deal with the struct body (bottom two branches)
    (
        (
            options = $ignore:tt,
            table_name = $table_name:ident,
            body = $($body:tt)*
        ),
        found_option_with_name = primary_key,
        value = $primary_key_names:tt,
    ) => {
        impl_Identifiable! {
            (
                table_name = $table_name,
                primary_key_names = $primary_key_names,
            )
            $($body)*
        }
    };

    // We found the primary key field, return the final impl
    (
        (
            table_name = $table_name:ident,
            struct_ty = $struct_ty:ty,
            lifetimes = ($($lifetimes:tt),*),
        ),
        found_fields_with_field_names,
        fields = [$({
            field_name: $field_name:ident,
            column_name: $column_name:ident,
            field_ty: $field_ty:ty,
            field_kind: $field_kind:ident,
            $($rest:tt)*
        })*],
    ) => {
        impl<$($lifetimes),*> $crate::associations::HasTable for $struct_ty {
            type Table = $table_name::table;

            fn table() -> Self::Table {
                $table_name::table
            }
        }

        impl<'ident $(,$lifetimes)*> $crate::associations::Identifiable for &'ident $struct_ty {
            type Id = ($(&'ident $field_ty),*);

            fn id(self) -> Self::Id {
                ($(&self.$field_name),*)
            }
        }
    };

    // Search for the primary key fields and continue
    (
        (
            table_name = $table_name:ident,
            primary_key_names = $primary_key_names:tt,
            $($args:tt)*
        ),
        fields = $fields:tt,
    ) => {
        __diesel_fields_with_field_names! {
            (table_name = $table_name, $($args)*),
            callback = impl_Identifiable,
            targets = $primary_key_names,
            fields = $fields,
        }
    };

    // Handle struct with generic lifetimes
    (
        ($($args:tt)*)
        $struct_name:ident <$($lifetimes:tt),*>
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                $($args)*
                struct_ty = $struct_name<$($lifetimes),*>,
                lifetimes = ($($lifetimes),*),
            ),
            callback = impl_Identifiable,
            body = $body,
        }
    };

    // Handle struct with no generics
    (
        ($($args:tt)*)
        $struct_name:ident
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                $($args)*
                struct_ty = $struct_name,
                lifetimes = (),
            ),
            callback = impl_Identifiable,
            body = $body,
        }
    };
}

#[cfg(test)]
mod test {
    table! {
        foos {
            id -> Integer,
        }
    }

    table! {
        bars {
            id -> VarChar,
        }
    }

    #[test]
    fn derive_identifiable_on_simple_struct() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations)]
        struct Foo {
            id: i32,
            #[allow(dead_code)]
            foo: i32,
        }

        impl_Identifiable! {
            #[table_name(foos)]
            struct Foo {
                id: i32,
                foo: i32,
            }
        }

        let foo1 = Foo { id: 1, foo: 2 };
        let foo2 = Foo { id: 2, foo: 3 };
        assert_eq!(&1, foo1.id());
        assert_eq!(&2, foo2.id());
    }

    #[test]
    fn derive_identifiable_when_id_is_not_first_field() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations)]
        struct Foo {
            #[allow(dead_code)]
            foo: i32,
            id: i32,
        }

        impl_Identifiable! {
            #[table_name(foos)]
            struct Foo {
                foo: i32,
                id: i32,
            }
        }

        let foo1 = Foo { id: 1, foo: 2 };
        let foo2 = Foo { id: 2, foo: 3 };
        assert_eq!(&1, foo1.id());
        assert_eq!(&2, foo2.id());
    }

    #[test]
    fn derive_identifiable_on_struct_with_non_integer_pk() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations)]
        struct Foo {
            id: &'static str,
            #[allow(dead_code)]
            foo: i32,
        }

        impl_Identifiable! {
            #[table_name(bars)]
            struct Foo {
                id: &'static str,
                foo: i32,
            }
        }

        let foo1 = Foo { id: "hi", foo: 2 };
        let foo2 = Foo { id: "there", foo: 3 };
        assert_eq!(&"hi", foo1.id());
        assert_eq!(&"there", foo2.id());
    }

    #[test]
    fn derive_identifiable_on_struct_with_lifetime() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations)]
        struct Foo<'a> {
            id: &'a str,
            #[allow(dead_code)]
            foo: i32,
        }

        impl_Identifiable! {
            #[table_name(bars)]
            struct Foo<'a> {
                id: &'a str,
                foo: i32,
            }
        }

        let foo1 = Foo { id: "hi", foo: 2 };
        let foo2 = Foo { id: "there", foo: 3 };
        assert_eq!(&"hi", foo1.id());
        assert_eq!(&"there", foo2.id());
    }

    #[test]
    fn derive_identifiable_with_non_standard_pk() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations, dead_code)]
        struct Foo<'a> {
            id: i32,
            foo_id: &'a str,
            foo: i32,
        }

        impl_Identifiable! {
            #[table_name(bars)]
            #[primary_key(foo_id)]
            struct Foo<'a> {
                id: i32,
                foo_id: &'a str,
                foo: i32,
            }
        }

        let foo1 = Foo { id: 1, foo_id: "hi", foo: 2 };
        let foo2 = Foo { id: 2, foo_id: "there", foo: 3 };
        assert_eq!(&"hi", foo1.id());
        assert_eq!(&"there", foo2.id());
    }

    #[test]
    fn derive_identifiable_with_non_standard_pk_given_before_table_name() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations, dead_code)]
        struct Foo<'a> {
            id: i32,
            foo_id: &'a str,
            foo: i32,
        }

        impl_Identifiable! {
            #[primary_key(foo_id)]
            #[table_name(bars)]
            struct Foo<'a> {
                id: i32,
                foo_id: &'a str,
                foo: i32,
            }
        }

        let foo1 = Foo { id: 1, foo_id: "hi", foo: 2 };
        let foo2 = Foo { id: 2, foo_id: "there", foo: 3 };
        assert_eq!(&"hi", foo1.id());
        assert_eq!(&"there", foo2.id());
    }

    #[test]
    fn derive_identifiable_with_composite_pk() {
        use associations::Identifiable;

        #[allow(missing_debug_implementations, missing_copy_implementations, dead_code)]
        struct Foo {
            id: i32,
            foo_id: i32,
            bar_id: i32,
            foo: i32,
        }

        impl_Identifiable! {
            #[primary_key(foo_id, bar_id)]
            #[table_name(bars)]
            struct Foo {
                id: i32,
                foo_id: i32,
                bar_id: i32,
                foo: i32,
            }
        }

        let foo1 = Foo { id: 1, foo_id: 2, bar_id: 3, foo: 4 };
        let foo2 = Foo { id: 5, foo_id: 6, bar_id: 7, foo: 8 };
        assert_eq!((&2, &3), foo1.id());
        assert_eq!((&6, &7), foo2.id());
    }
}<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use gc_error::{GcError, Result};
use types::js_var::JsPtrEnum;
use types::binding::UniqueBinding;

pub type Alloc<T> = Rc<RefCell<T>>;

#[derive(Debug)]
pub struct AllocBox {
    black_set: HashMap<UniqueBinding, Alloc<JsPtrEnum>>,
    grey_set: HashMap<UniqueBinding, Alloc<JsPtrEnum>>,
    white_set: HashMap<UniqueBinding, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn alloc(&mut self, binding: UniqueBinding, ptr: JsPtrEnum) -> Result<()> {
        if self.grey_set.insert(binding.clone(), Rc::new(RefCell::new(ptr))).is_none() {
            Ok(())
        } else {
            // If a binding already exists and we try to allocate it, this should
            // be an unrecoverable error, as we may be clobbering data that someone
            // else has reference to.
            Err(GcError::Alloc(binding))
        }
    }

    pub fn condemn(&mut self, unique: UniqueBinding) -> Result<()> {
        if let Some(ptr) = self.remove_binding(&unique) {
            self.white_set.insert(unique, ptr);
            Ok(())
        } else {
            Err(GcError::HeapUpdate)
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (bnd, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(bnd, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set.clear();
        // TODO is it a good assumption to reset everything to grey?
        self.grey_set = self.black_set.drain().collect();
        self.black_set.clear();
    }

    pub fn find_id(&self, bnd: &UniqueBinding) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(bnd).or(
            self.grey_set.get(bnd).or(
                self.black_set.get(bnd)))
    }

    pub fn is_allocated(&self, bnd: &UniqueBinding) -> bool {
        self.white_set.contains_key(bnd) ||
        self.grey_set.contains_key(bnd)  ||
        self.black_set.contains_key(bnd)
    }

    pub fn update_ptr(&mut self, binding: &UniqueBinding, ptr: JsPtrEnum) -> Result<()> {
        // Updating a pointer means it is definitely reachable
        if let Some(alloc) = self.remove_binding(binding) {
            *alloc.borrow_mut() = ptr;
            self.grey_set.insert(binding.clone(), alloc);
            Ok(())
        } else {
            Err(GcError::HeapUpdate)
        }
    }

    fn remove_binding(&mut self, binding: &UniqueBinding) -> Option<Alloc<JsPtrEnum>> {
        self.white_set.remove(binding).or(
            self.grey_set.remove(binding).or(
                self.black_set.remove(binding)))
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<UniqueBinding> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use gc_error::GcError;
    use types::binding::UniqueBinding;
    use types::js_var::JsPtrEnum;
    use types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_len() {
        let mut ab = AllocBox::new();
        assert!(ab.is_empty());
        assert!(ab.alloc(UniqueBinding::anon(), test_utils::make_str("").1).is_ok());
        assert_eq!(ab.len(), 1);
    }

    #[test]
    fn test_alloc() {
        let mut ab = AllocBox::new();
        let (x, x_ptr) = test_utils::make_str("x");
        let (y, y_ptr) = test_utils::make_str("y");
        assert!(ab.alloc(x.unique, x_ptr.clone()).is_ok());
        assert!(ab.alloc(y.unique, y_ptr).is_ok());
    }

    #[test]
    fn test_alloc_fail() {
        let mut ab = AllocBox::new();
        let (x, x_ptr) = test_utils::make_str("x");
        assert!(ab.alloc(x.unique.clone(), x_ptr.clone()).is_ok());
        let res = ab.alloc(x.unique.clone(), x_ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::Alloc(_))));
        if let Err(GcError::Alloc(bnd)) = res {
            assert_eq!(x.unique, bnd);
        }
    }

    #[test]
    fn test_update_ptr() {
        let mut ab = AllocBox::new();
        let (x, x_ptr) = test_utils::make_str("x");
        assert!(ab.alloc(x.unique.clone(), x_ptr.clone()).is_ok());
        let (_, new_ptr) = test_utils::make_str("y");
        assert!(ab.update_ptr(&x.unique, new_ptr).is_ok());
        let opt_ptr = ab.find_id(&x.unique);
        assert!(opt_ptr.is_some());
        // Hack to get around some borrowck failures I don't fully understand
        if let Some(ptr) = opt_ptr {
            match ptr.borrow().clone() {
                JsPtrEnum::JsStr(JsStrStruct { ref text }) => assert_eq!(text.clone(), "y".to_string()),
                _ => unreachable!(),
            }
        } else {
            unreachable!()
        }
    }

    #[test]
    fn test_update_ptr_fail() {
        let mut ab = AllocBox::new();
        let (_, ptr) = test_utils::make_str("");
        let res = ab.update_ptr(&UniqueBinding::anon(), ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::HeapUpdate)));
    }
}
<commit_msg>Change AllocBox::sweep_ptrs to drop old hashmaps when sweeping<commit_after>use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use gc_error::{GcError, Result};
use types::js_var::JsPtrEnum;
use types::binding::UniqueBinding;

pub type Alloc<T> = Rc<RefCell<T>>;

#[derive(Debug)]
pub struct AllocBox {
    black_set: HashMap<UniqueBinding, Alloc<JsPtrEnum>>,
    grey_set: HashMap<UniqueBinding, Alloc<JsPtrEnum>>,
    white_set: HashMap<UniqueBinding, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn alloc(&mut self, binding: UniqueBinding, ptr: JsPtrEnum) -> Result<()> {
        if self.grey_set.insert(binding.clone(), Rc::new(RefCell::new(ptr))).is_none() {
            Ok(())
        } else {
            // If a binding already exists and we try to allocate it, this should
            // be an unrecoverable error, as we may be clobbering data that someone
            // else has reference to.
            Err(GcError::Alloc(binding))
        }
    }

    pub fn condemn(&mut self, unique: UniqueBinding) -> Result<()> {
        if let Some(ptr) = self.remove_binding(&unique) {
            self.white_set.insert(unique, ptr);
            Ok(())
        } else {
            Err(GcError::HeapUpdate)
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (bnd, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(bnd, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = HashMap::new();
        // TODO is it a good assumption to reset everything to grey?
        self.grey_set = self.black_set.drain().collect();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, bnd: &UniqueBinding) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(bnd).or(
            self.grey_set.get(bnd).or(
                self.black_set.get(bnd)))
    }

    pub fn is_allocated(&self, bnd: &UniqueBinding) -> bool {
        self.white_set.contains_key(bnd) ||
        self.grey_set.contains_key(bnd)  ||
        self.black_set.contains_key(bnd)
    }

    pub fn update_ptr(&mut self, binding: &UniqueBinding, ptr: JsPtrEnum) -> Result<()> {
        // Updating a pointer means it is definitely reachable
        if let Some(alloc) = self.remove_binding(binding) {
            *alloc.borrow_mut() = ptr;
            self.grey_set.insert(binding.clone(), alloc);
            Ok(())
        } else {
            Err(GcError::HeapUpdate)
        }
    }

    fn remove_binding(&mut self, binding: &UniqueBinding) -> Option<Alloc<JsPtrEnum>> {
        self.white_set.remove(binding).or(
            self.grey_set.remove(binding).or(
                self.black_set.remove(binding)))
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<UniqueBinding> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use gc_error::GcError;
    use types::binding::UniqueBinding;
    use types::js_var::JsPtrEnum;
    use types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_len() {
        let mut ab = AllocBox::new();
        assert!(ab.is_empty());
        assert!(ab.alloc(UniqueBinding::anon(), test_utils::make_str("").1).is_ok());
        assert_eq!(ab.len(), 1);
    }

    #[test]
    fn test_alloc() {
        let mut ab = AllocBox::new();
        let (x, x_ptr) = test_utils::make_str("x");
        let (y, y_ptr) = test_utils::make_str("y");
        assert!(ab.alloc(x.unique, x_ptr.clone()).is_ok());
        assert!(ab.alloc(y.unique, y_ptr).is_ok());
    }

    #[test]
    fn test_alloc_fail() {
        let mut ab = AllocBox::new();
        let (x, x_ptr) = test_utils::make_str("x");
        assert!(ab.alloc(x.unique.clone(), x_ptr.clone()).is_ok());
        let res = ab.alloc(x.unique.clone(), x_ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::Alloc(_))));
        if let Err(GcError::Alloc(bnd)) = res {
            assert_eq!(x.unique, bnd);
        }
    }

    #[test]
    fn test_update_ptr() {
        let mut ab = AllocBox::new();
        let (x, x_ptr) = test_utils::make_str("x");
        assert!(ab.alloc(x.unique.clone(), x_ptr.clone()).is_ok());
        let (_, new_ptr) = test_utils::make_str("y");
        assert!(ab.update_ptr(&x.unique, new_ptr).is_ok());
        let opt_ptr = ab.find_id(&x.unique);
        assert!(opt_ptr.is_some());
        // Hack to get around some borrowck failures I don't fully understand
        if let Some(ptr) = opt_ptr {
            match ptr.borrow().clone() {
                JsPtrEnum::JsStr(JsStrStruct { ref text }) => assert_eq!(text.clone(), "y".to_string()),
                _ => unreachable!(),
            }
        } else {
            unreachable!()
        }
    }

    #[test]
    fn test_update_ptr_fail() {
        let mut ab = AllocBox::new();
        let (_, ptr) = test_utils::make_str("");
        let res = ab.update_ptr(&UniqueBinding::anon(), ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::HeapUpdate)));
    }
}
<|endoftext|>


<commit_before>use approx::RelativeEq;
use num::Num;
use num_complex::Complex;
#[cfg(feature = "decimal")]
use decimal::d128;

use general::wrapper::Wrapper as W;
use general::{
    AbstractGroupAbelian, AbstractMonoid, Additive, ClosedNeg, Multiplicative, Operator,
};

/// A **ring** is the combination of an Abelian group and a multiplicative monoid structure.
///
/// A ring is equipped with:
///
/// * An abstract operator (usually the addition, "+") that fulfills the constraints of an Abelian group.
///
///     *An Abelian group is a set with a closed commutative and associative addition with the divisibility property and an identity element.*
/// * A second abstract operator (usually the multiplication, "×") that fulfills the constraints of a monoid.
///
///     *A set equipped with a closed associative multiplication with the divisibility property and an identity element.*
///
/// The multiplication is distributive over the addition:
///
/// # Distributivity
///
/// ~~~notrust
/// a, b, c ∈ Self, a × (b + c) = a × b + a × c.
/// ~~~
pub trait AbstractRing<A: Operator = Additive, M: Operator = Multiplicative>:
    AbstractGroupAbelian<A> + AbstractMonoid<M>
{
    /// Returns `true` if the multiplication and addition operators are distributive for
    /// the given argument tuple. Approximate equality is used for verifications.
    fn prop_mul_and_add_are_distributive_approx(args: (Self, Self, Self)) -> bool
    where
        Self: RelativeEq,
    {
        let (a, b, c) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());
        let c = || W::<_, A, M>::new(c.clone());

        // Left distributivity
        relative_eq!(a() * (b() + c()), a() * b() + a() * c()) &&
        // Right distributivity
        relative_eq!((b() + c()) * a(), b() * a() + c() * a())
    }

    /// Returns `true` if the multiplication and addition operators are distributive for
    /// the given argument tuple.
    fn prop_mul_and_add_are_distributive(args: (Self, Self, Self)) -> bool
    where
        Self: Eq,
    {
        let (a, b, c) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());
        let c = || W::<_, A, M>::new(c.clone());

        // Left distributivity
        (a() * b()) + c() == (a() * b()) + (a() * c()) &&
        // Right distributivity
        (b() + c()) * a() == (b() * a()) + (c() * a())
    }
}

/// Implements the ring trait for types provided.
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate alga;
/// # use alga::general::{AbstractMagma, AbstractRing, Additive, Multiplicative, Inverse, Identity};
/// # fn main() {}
/// #[derive(PartialEq, Clone)]
/// struct Wrapper<T>(T);
///
/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Inverse<Additive>> Inverse<Additive> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl<T: AbstractMagma<Multiplicative>> AbstractMagma<Multiplicative> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Identity<Multiplicative>> Identity<Multiplicative> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl_ring!(<Additive, Multiplicative> for Wrapper<T> where T: AbstractRing);
/// ```
macro_rules! impl_ring(
    (<$A:ty, $M:ty> for $($T:tt)+) => {
        impl_abelian!(<$A> for $($T)+);
        impl_monoid!(<$M> for $($T)+);
        impl_marker!($crate::general::AbstractRing<$A, $M>; $($T)+);
    }
);

/// A ring with a commutative multiplication.
///
/// *A **commutative ring** is a set with two binary operations: a closed commutative and associative with the divisibility property and an identity element,
/// and another closed associative and **commutative** with the divisibility property and an identity element.*
///
/// # Commutativity
///
/// ```notrust
/// ∀ a, b ∈ Self, a × b = b × a
/// ```
pub trait AbstractRingCommutative<A: Operator = Additive, M: Operator = Multiplicative>:
    AbstractRing<A, M>
{
    /// Returns `true` if the multiplication operator is commutative for the given argument tuple.
    /// Approximate equality is used for verifications.
    fn prop_mul_is_commutative_approx(args: (Self, Self)) -> bool
    where
        Self: RelativeEq,
    {
        let (a, b) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());

        relative_eq!(a() * b(), b() * a())
    }

    /// Returns `true` if the multiplication operator is commutative for the given argument tuple.
    fn prop_mul_is_commutative(args: (Self, Self)) -> bool
    where
        Self: Eq,
    {
        let (a, b) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());

        a() * b() == b() * a()
    }
}

/// Implements the commutative ring trait for types provided.
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate alga;
/// # use alga::general::{AbstractMagma, AbstractRingCommutative, Additive, Multiplicative, Inverse, Identity};
/// # fn main() {}
/// #[derive(PartialEq, Clone)]
/// struct Wrapper<T>(T);
///
/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Inverse<Additive>> Inverse<Additive> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl<T: AbstractMagma<Multiplicative>> AbstractMagma<Multiplicative> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Identity<Multiplicative>> Identity<Multiplicative> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl_ring!(<Additive, Multiplicative> for Wrapper<T> where T: AbstractRingCommutative);
/// ```
macro_rules! impl_ring_commutative(
    (<$A:ty, $M:ty> for $($T:tt)+) => {
        impl_ring!(<$A, $M> for $($T)+);
        impl_marker!($crate::general::AbstractRingCommutative<$A, $M>; $($T)+);
    }
);

/// A field is a commutative ring, and an Abelian group under both operators.
///
/// *A **field** is a set with two binary operations, an addition and a multiplication, which are both closed, commutative, associative
/// possess the divisibility property and an identity element, noted 0 and 1 respectively. Furthermore the multiplication is distributive
/// over the addition.*
pub trait AbstractField<A: Operator = Additive, M: Operator = Multiplicative>:
    AbstractRingCommutative<A, M> + AbstractGroupAbelian<M>
{
}

/// Implements the field trait for types provided.
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate alga;
/// # use alga::general::{AbstractMagma, AbstractField, Additive, Multiplicative, Inverse, Identity};
/// # fn main() {}
/// #[derive(PartialEq, Clone)]
/// struct Wrapper<T>(T);
///
/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Inverse<Additive>> Inverse<Additive> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl<T: AbstractMagma<Multiplicative>> AbstractMagma<Multiplicative> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
/// impl<T: Inverse<Multiplicative>> Inverse<Multiplicative> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Multiplicative>> Identity<Multiplicative> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl_field!(<Additive, Multiplicative> for Wrapper<T> where T: AbstractField);
/// ```
macro_rules! impl_field(
    (<$A:ty, $M:ty> for $($T:tt)+) => {
        impl_ring_commutative!(<$A, $M> for $($T)+);
        impl_marker!($crate::general::AbstractQuasigroup<$M>; $($T)+);
        impl_marker!($crate::general::AbstractLoop<$M>; $($T)+);
        impl_marker!($crate::general::AbstractGroup<$M>; $($T)+);
        impl_marker!($crate::general::AbstractGroupAbelian<$M>; $($T)+);
        impl_marker!($crate::general::AbstractField<$A, $M>; $($T)+);
    }
);

/*
 *
 * Implementations.
 *
 */
impl_ring_commutative!(<Additive, Multiplicative> for i8; i16; i32; i64; isize);
impl_field!(<Additive, Multiplicative> for f32; f64);
#[cfg(feature = "decimal")]
impl_field!(<Additive, Multiplicative> for d128);

impl<N: Num + Clone + ClosedNeg + AbstractRing> AbstractRing for Complex<N> {}
impl<N: Num + Clone + ClosedNeg + AbstractRingCommutative> AbstractRingCommutative for Complex<N> {}
impl<N: Num + Clone + ClosedNeg + AbstractField> AbstractField for Complex<N> {}
<commit_msg>fix AbstractRing distributive property test<commit_after>use approx::RelativeEq;
use num::Num;
use num_complex::Complex;
#[cfg(feature = "decimal")]
use decimal::d128;

use general::wrapper::Wrapper as W;
use general::{
    AbstractGroupAbelian, AbstractMonoid, Additive, ClosedNeg, Multiplicative, Operator,
};

/// A **ring** is the combination of an Abelian group and a multiplicative monoid structure.
///
/// A ring is equipped with:
///
/// * An abstract operator (usually the addition, "+") that fulfills the constraints of an Abelian group.
///
///     *An Abelian group is a set with a closed commutative and associative addition with the divisibility property and an identity element.*
/// * A second abstract operator (usually the multiplication, "×") that fulfills the constraints of a monoid.
///
///     *A set equipped with a closed associative multiplication with the divisibility property and an identity element.*
///
/// The multiplication is distributive over the addition:
///
/// # Distributivity
///
/// ~~~notrust
/// a, b, c ∈ Self, a × (b + c) = a × b + a × c.
/// ~~~
pub trait AbstractRing<A: Operator = Additive, M: Operator = Multiplicative>:
    AbstractGroupAbelian<A> + AbstractMonoid<M>
{
    /// Returns `true` if the multiplication and addition operators are distributive for
    /// the given argument tuple. Approximate equality is used for verifications.
    fn prop_mul_and_add_are_distributive_approx(args: (Self, Self, Self)) -> bool
    where
        Self: RelativeEq,
    {
        let (a, b, c) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());
        let c = || W::<_, A, M>::new(c.clone());

        // Left distributivity
        relative_eq!(a() * (b() + c()), a() * b() + a() * c()) &&
        // Right distributivity
        relative_eq!((b() + c()) * a(), b() * a() + c() * a())
    }

    /// Returns `true` if the multiplication and addition operators are distributive for
    /// the given argument tuple.
    fn prop_mul_and_add_are_distributive(args: (Self, Self, Self)) -> bool
    where
        Self: Eq,
    {
        let (a, b, c) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());
        let c = || W::<_, A, M>::new(c.clone());

        // Left distributivity
        a() * (b() + c()) == (a() * b()) + (a() * c()) &&
        // Right distributivity
        (b() + c()) * a() == (b() * a()) + (c() * a())
    }
}

/// Implements the ring trait for types provided.
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate alga;
/// # use alga::general::{AbstractMagma, AbstractRing, Additive, Multiplicative, Inverse, Identity};
/// # fn main() {}
/// #[derive(PartialEq, Clone)]
/// struct Wrapper<T>(T);
///
/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Inverse<Additive>> Inverse<Additive> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl<T: AbstractMagma<Multiplicative>> AbstractMagma<Multiplicative> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Identity<Multiplicative>> Identity<Multiplicative> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl_ring!(<Additive, Multiplicative> for Wrapper<T> where T: AbstractRing);
/// ```
macro_rules! impl_ring(
    (<$A:ty, $M:ty> for $($T:tt)+) => {
        impl_abelian!(<$A> for $($T)+);
        impl_monoid!(<$M> for $($T)+);
        impl_marker!($crate::general::AbstractRing<$A, $M>; $($T)+);
    }
);

/// A ring with a commutative multiplication.
///
/// *A **commutative ring** is a set with two binary operations: a closed commutative and associative with the divisibility property and an identity element,
/// and another closed associative and **commutative** with the divisibility property and an identity element.*
///
/// # Commutativity
///
/// ```notrust
/// ∀ a, b ∈ Self, a × b = b × a
/// ```
pub trait AbstractRingCommutative<A: Operator = Additive, M: Operator = Multiplicative>:
    AbstractRing<A, M>
{
    /// Returns `true` if the multiplication operator is commutative for the given argument tuple.
    /// Approximate equality is used for verifications.
    fn prop_mul_is_commutative_approx(args: (Self, Self)) -> bool
    where
        Self: RelativeEq,
    {
        let (a, b) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());

        relative_eq!(a() * b(), b() * a())
    }

    /// Returns `true` if the multiplication operator is commutative for the given argument tuple.
    fn prop_mul_is_commutative(args: (Self, Self)) -> bool
    where
        Self: Eq,
    {
        let (a, b) = args;
        let a = || W::<_, A, M>::new(a.clone());
        let b = || W::<_, A, M>::new(b.clone());

        a() * b() == b() * a()
    }
}

/// Implements the commutative ring trait for types provided.
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate alga;
/// # use alga::general::{AbstractMagma, AbstractRingCommutative, Additive, Multiplicative, Inverse, Identity};
/// # fn main() {}
/// #[derive(PartialEq, Clone)]
/// struct Wrapper<T>(T);
///
/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Inverse<Additive>> Inverse<Additive> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl<T: AbstractMagma<Multiplicative>> AbstractMagma<Multiplicative> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Identity<Multiplicative>> Identity<Multiplicative> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl_ring!(<Additive, Multiplicative> for Wrapper<T> where T: AbstractRingCommutative);
/// ```
macro_rules! impl_ring_commutative(
    (<$A:ty, $M:ty> for $($T:tt)+) => {
        impl_ring!(<$A, $M> for $($T)+);
        impl_marker!($crate::general::AbstractRingCommutative<$A, $M>; $($T)+);
    }
);

/// A field is a commutative ring, and an Abelian group under both operators.
///
/// *A **field** is a set with two binary operations, an addition and a multiplication, which are both closed, commutative, associative
/// possess the divisibility property and an identity element, noted 0 and 1 respectively. Furthermore the multiplication is distributive
/// over the addition.*
pub trait AbstractField<A: Operator = Additive, M: Operator = Multiplicative>:
    AbstractRingCommutative<A, M> + AbstractGroupAbelian<M>
{
}

/// Implements the field trait for types provided.
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate alga;
/// # use alga::general::{AbstractMagma, AbstractField, Additive, Multiplicative, Inverse, Identity};
/// # fn main() {}
/// #[derive(PartialEq, Clone)]
/// struct Wrapper<T>(T);
///
/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
///
/// impl<T: Inverse<Additive>> Inverse<Additive> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl<T: AbstractMagma<Multiplicative>> AbstractMagma<Multiplicative> for Wrapper<T> {
///     fn operate(&self, right: &Self) -> Self {
///         Wrapper(self.0.operate(&right.0))
///     }
/// }
/// impl<T: Inverse<Multiplicative>> Inverse<Multiplicative> for Wrapper<T> {
///     fn inverse(&self) -> Self {
///         Wrapper(self.0.inverse())
///     }
/// }
///
/// impl<T: Identity<Multiplicative>> Identity<Multiplicative> for Wrapper<T> {
///     fn identity() -> Self {
///         Wrapper(T::identity())
///     }
/// }
///
/// impl_field!(<Additive, Multiplicative> for Wrapper<T> where T: AbstractField);
/// ```
macro_rules! impl_field(
    (<$A:ty, $M:ty> for $($T:tt)+) => {
        impl_ring_commutative!(<$A, $M> for $($T)+);
        impl_marker!($crate::general::AbstractQuasigroup<$M>; $($T)+);
        impl_marker!($crate::general::AbstractLoop<$M>; $($T)+);
        impl_marker!($crate::general::AbstractGroup<$M>; $($T)+);
        impl_marker!($crate::general::AbstractGroupAbelian<$M>; $($T)+);
        impl_marker!($crate::general::AbstractField<$A, $M>; $($T)+);
    }
);

/*
 *
 * Implementations.
 *
 */
impl_ring_commutative!(<Additive, Multiplicative> for i8; i16; i32; i64; isize);
impl_field!(<Additive, Multiplicative> for f32; f64);
#[cfg(feature = "decimal")]
impl_field!(<Additive, Multiplicative> for d128);

impl<N: Num + Clone + ClosedNeg + AbstractRing> AbstractRing for Complex<N> {}
impl<N: Num + Clone + ClosedNeg + AbstractRingCommutative> AbstractRingCommutative for Complex<N> {}
impl<N: Num + Clone + ClosedNeg + AbstractField> AbstractField for Complex<N> {}
<|endoftext|>


<commit_before>/* CONFIGURATION */

// add other android system headers to this list as necessary
static INCLUDE_SYS_H: [&str; 1] = ["jni.h"];

static RUST_SRC_DIR: &str = "src";
static ANDROID_BASE_DIR: &str = "app";

// =========================================================
// This script is portable; copy and paste it into your own
// build files at will.

extern crate bindgen;
extern crate rust_swig;
extern crate syntex;
extern crate walkdir;

use std::process::{Command, Stdio};
use std::{env, fmt};
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use bindgen::RustTarget;
use rust_swig::{JavaConfig, LanguageConfig};
use walkdir::WalkDir;

fn main() {
    let target = env::var("TARGET").unwrap();
    assert!(["aarch64-linux-android", "arm-linux-androideabi",
             "i686-linux-android", "x86_64-linux-android"].contains(&target.as_str()));

    let include_dirs =
        get_gcc_system_include_dirs().expect("Can't get gcc's system include dirs");

    let include_headers: Vec<_> = INCLUDE_SYS_H.into_iter()
        .map(|h| search_file_in_directory(&include_dirs, h)
             .expect(format!("Could not find header {}", h).as_ref()))
        .collect();

    let src_dir = Path::new(RUST_SRC_DIR);
    let out_dir = env::var("OUT_DIR").unwrap();

    gen_binding(
        &target,
        &include_dirs,
        &include_headers,
        &Path::new(&out_dir).join("android_c_headers.rs"),
    ).unwrap();

    // Find files ending in .rs.in and expand them with SWIG
    for _entry in WalkDir::new(RUST_SRC_DIR) {
        let entry = _entry.expect("Error walking sources.");
        if entry.path().is_dir() || !entry.path().to_string_lossy().ends_with(".rs.in") {
            continue;
        }

        println!("Found SWIG specification: {}", entry.path().display());
        let swigf = entry.path().strip_prefix("src").unwrap();

        rust_swig_expand(
            &src_dir,
            &swigf,
            Path::new(&out_dir),
        ).unwrap();

        write_include_file(&src_dir, swigf).expect("Failed to write include file.");
    }

    // Hook up cargo reruns
    println!("cargo:rerun-if-changed={}", RUST_SRC_DIR);
    for dir in &include_dirs {println!("cargo:rerun-if-changed={}", dir.display());}
    //if the generated files were deleted (e.g by gradle -q clean), regenerate them
    println!("cargo:rerun-if-changed={}", out_dir);
}

fn get_gcc_system_include_dirs() -> Result<Vec<PathBuf>, String> {
    let gcc_cmd = env::var("LINKER").expect("LINKER not set --
Update your version of Cargo or merge PR#5394 from github.com/rust-lang/cargo.");
    println!("Using Android gcc from '{}'", gcc_cmd);

    let gcc_process = Command::new(&gcc_cmd)
        .args(&["-v", "-x", "c", "-E", "-" /*, &("--sysroot=".to_owned() + &sysroot)*/])
        .stderr(Stdio::piped())
        .stdin(Stdio::piped())
        .stdout(Stdio::inherit())
        .spawn()
        .map_err(|err| err.to_string())?;

    gcc_process
        .stdin
        .ok_or(format!("Cannot get stdin of {}", gcc_cmd).as_str())?
        .write_all("\n".as_bytes())
        .map_err(|err| err.to_string())?;

    let mut gcc_output = String::new();
    gcc_process
        .stderr
        .ok_or(format!("Cannot get stderr of {}", gcc_cmd).as_str())?
        .read_to_string(&mut gcc_output)
        .map_err(|err| err.to_string())?;

    const BEGIN_PAT: &'static str = "\n#include <...> search starts here:\n";
    const END_PAT: &'static str = "\nEnd of search list.\n";
    let start_includes = gcc_output
        .find(BEGIN_PAT)
        .ok_or(format!("No '{}' in output from {}", BEGIN_PAT, gcc_cmd).as_str())?
        + BEGIN_PAT.len();
    let end_includes = (&gcc_output[start_includes..])
        .find(END_PAT)
        .ok_or(format!("No '{}' in output from {}", END_PAT, gcc_cmd).as_str())?
        + start_includes;

    Ok((&gcc_output[start_includes..end_includes])
       .split('\n')
       .map(|s| PathBuf::from(s.trim().to_string()))
       .collect())
}

fn search_file_in_directory<P>(dirs: &[P], file: &str) -> Result<PathBuf, ()>
where
    P: AsRef<Path>,
{
    for dir in dirs {
        let file_path = dir.as_ref().join(file);
        if file_path.exists() && file_path.is_file() {
            return Ok(file_path);
        }
    }
    Err(())
}

fn gen_binding<P1, P2>(
    target: &str,
    include_dirs: &[P1],
    c_headers: &[P2],
    output_rust: &Path,
) -> Result<(), String>
where
    P1: AsRef<Path> + fmt::Debug,
    P2: AsRef<Path> + fmt::Debug,
{
    assert!(!c_headers.is_empty());
    let c_file_path = &c_headers[0];

    let mut bindings: bindgen::Builder =
        bindgen::builder().header(c_file_path.as_ref().to_str().unwrap());
    bindings = include_dirs.iter().fold(bindings, |acc, x| {
        acc.clang_arg("-I".to_string() + x.as_ref().to_str().unwrap())
    });
    println!("Generate binding for {:?}", c_headers);
    bindings = bindings
        .rust_target(RustTarget::Stable_1_19)
    //long double not supported yet, see https://github.com/servo/rust-bindgen/issues/550
        .blacklist_type("max_align_t");
    bindings = if target.contains("windows") {
        //see https://github.com/servo/rust-bindgen/issues/578
        bindings.trust_clang_mangling(false)
    } else {
        bindings
    };
    bindings = c_headers[1..].iter().fold(
        Ok(bindings),
        |acc: Result<bindgen::Builder, String>, header| {
            let c_file_path = header;
            let c_file_str = c_file_path
                .as_ref()
                .to_str()
                .ok_or_else(|| format!("Invalid unicode in path to {:?}", c_file_path.as_ref()))?;
            Ok(acc.unwrap().clang_arg("-include").clang_arg(c_file_str))
        },
    )?;

    let generated_bindings = bindings
    //        .clang_arg(format!("-target {}", target))
        .generate()
        .map_err(|_| "Failed to generate bindings".to_string())?;
    generated_bindings
        .write_to_file(output_rust)
        .map_err(|err| err.to_string())?;

    Ok(())
}

fn rust_swig_expand(source_dir: &Path, file: &Path, out_dir: &Path) -> Result<(), String> {
    let app_id = env::var("ANDROID_APPLICATION_ID")
        .expect("You must set ANDROID_APPLICATION_ID to the package name of your android application.");

    let mut registry = syntex::Registry::new();
    let swig_gen = rust_swig::Generator::new(LanguageConfig::JavaConfig(
        JavaConfig::new(
            Path::new(ANDROID_BASE_DIR)
                .join("src")
                .join("main")
                .join("java")
                .join(app_id.replace(".", "/")),
            app_id.to_owned() // not sure why it requires ownership...
        ).use_null_annotation("android.support.annotation.NonNull".into()),
    ));
    swig_gen.register(&mut registry);

    let out_file = out_dir.join(Path::new(file.parent().unwrap_or(Path::new(".")))
                                .join(file.file_stem().expect("Got invalid file (no filename)")));

    registry
        .expand(app_id.as_ref(), source_dir.join(file), out_file)
        .map_err(|err| format!("Rust-SWIG expansion failed: {}", err))
}

fn write_include_file(source_dir: &Path, swig_file: &Path) -> std::io::Result<()> {
    let rs_rel_file = Path::new(swig_file.parent().unwrap_or(Path::new(".")))
        .join(swig_file.file_stem().expect("Got invalid file (no filename)"));
    let rs_path = source_dir.join(&rs_rel_file);

    if rs_path.exists() {
        println!("Not writing {} because it exists", rs_path.display());
        return Ok(());
    }

    let mut rs_file = File::create(rs_path)?;
    rs_file.write_all(format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}\"",
                              rs_rel_file.to_string_lossy()).as_bytes())?;

    return Ok(());
}
<commit_msg>Changed name of LINKER env var to RUSTC_LINKER<commit_after>/* CONFIGURATION */

// add other android system headers to this list as necessary
static INCLUDE_SYS_H: [&str; 1] = ["jni.h"];

static RUST_SRC_DIR: &str = "src";
static ANDROID_BASE_DIR: &str = "app";

// =========================================================
// This script is portable; copy and paste it into your own
// build files at will.

extern crate bindgen;
extern crate rust_swig;
extern crate syntex;
extern crate walkdir;

use std::process::{Command, Stdio};
use std::{env, fmt};
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use bindgen::RustTarget;
use rust_swig::{JavaConfig, LanguageConfig};
use walkdir::WalkDir;

fn main() {
    let target = env::var("TARGET").unwrap();
    assert!(["aarch64-linux-android", "arm-linux-androideabi",
             "i686-linux-android", "x86_64-linux-android"].contains(&target.as_str()));

    let include_dirs =
        get_gcc_system_include_dirs().expect("Can't get gcc's system include dirs");

    let include_headers: Vec<_> = INCLUDE_SYS_H.into_iter()
        .map(|h| search_file_in_directory(&include_dirs, h)
             .expect(format!("Could not find header {}", h).as_ref()))
        .collect();

    let src_dir = Path::new(RUST_SRC_DIR);
    let out_dir = env::var("OUT_DIR").unwrap();

    gen_binding(
        &target,
        &include_dirs,
        &include_headers,
        &Path::new(&out_dir).join("android_c_headers.rs"),
    ).unwrap();

    // Find files ending in .rs.in and expand them with SWIG
    for _entry in WalkDir::new(RUST_SRC_DIR) {
        let entry = _entry.expect("Error walking sources.");
        if entry.path().is_dir() || !entry.path().to_string_lossy().ends_with(".rs.in") {
            continue;
        }

        println!("Found SWIG specification: {}", entry.path().display());
        let swigf = entry.path().strip_prefix("src").unwrap();

        rust_swig_expand(
            &src_dir,
            &swigf,
            Path::new(&out_dir),
        ).unwrap();

        write_include_file(&src_dir, swigf).expect("Failed to write include file.");
    }

    // Hook up cargo reruns
    println!("cargo:rerun-if-changed={}", RUST_SRC_DIR);
    for dir in &include_dirs {println!("cargo:rerun-if-changed={}", dir.display());}
    //if the generated files were deleted (e.g by gradle -q clean), regenerate them
    println!("cargo:rerun-if-changed={}", out_dir);
}

fn get_gcc_system_include_dirs() -> Result<Vec<PathBuf>, String> {
    let gcc_cmd = env::var("RUSTC_LINKER").expect("RUSTC_LINKER not set --
Update your version of Cargo or merge PR#5394 from github.com/rust-lang/cargo.");
    println!("Using Android gcc from '{}'", gcc_cmd);

    let gcc_process = Command::new(&gcc_cmd)
        .args(&["-v", "-x", "c", "-E", "-" /*, &("--sysroot=".to_owned() + &sysroot)*/])
        .stderr(Stdio::piped())
        .stdin(Stdio::piped())
        .stdout(Stdio::inherit())
        .spawn()
        .map_err(|err| err.to_string())?;

    gcc_process
        .stdin
        .ok_or(format!("Cannot get stdin of {}", gcc_cmd).as_str())?
        .write_all("\n".as_bytes())
        .map_err(|err| err.to_string())?;

    let mut gcc_output = String::new();
    gcc_process
        .stderr
        .ok_or(format!("Cannot get stderr of {}", gcc_cmd).as_str())?
        .read_to_string(&mut gcc_output)
        .map_err(|err| err.to_string())?;

    const BEGIN_PAT: &'static str = "\n#include <...> search starts here:\n";
    const END_PAT: &'static str = "\nEnd of search list.\n";
    let start_includes = gcc_output
        .find(BEGIN_PAT)
        .ok_or(format!("No '{}' in output from {}", BEGIN_PAT, gcc_cmd).as_str())?
        + BEGIN_PAT.len();
    let end_includes = (&gcc_output[start_includes..])
        .find(END_PAT)
        .ok_or(format!("No '{}' in output from {}", END_PAT, gcc_cmd).as_str())?
        + start_includes;

    Ok((&gcc_output[start_includes..end_includes])
       .split('\n')
       .map(|s| PathBuf::from(s.trim().to_string()))
       .collect())
}

fn search_file_in_directory<P>(dirs: &[P], file: &str) -> Result<PathBuf, ()>
where
    P: AsRef<Path>,
{
    for dir in dirs {
        let file_path = dir.as_ref().join(file);
        if file_path.exists() && file_path.is_file() {
            return Ok(file_path);
        }
    }
    Err(())
}

fn gen_binding<P1, P2>(
    target: &str,
    include_dirs: &[P1],
    c_headers: &[P2],
    output_rust: &Path,
) -> Result<(), String>
where
    P1: AsRef<Path> + fmt::Debug,
    P2: AsRef<Path> + fmt::Debug,
{
    assert!(!c_headers.is_empty());
    let c_file_path = &c_headers[0];

    let mut bindings: bindgen::Builder =
        bindgen::builder().header(c_file_path.as_ref().to_str().unwrap());
    bindings = include_dirs.iter().fold(bindings, |acc, x| {
        acc.clang_arg("-I".to_string() + x.as_ref().to_str().unwrap())
    });
    println!("Generate binding for {:?}", c_headers);
    bindings = bindings
        .rust_target(RustTarget::Stable_1_19)
    //long double not supported yet, see https://github.com/servo/rust-bindgen/issues/550
        .blacklist_type("max_align_t");
    bindings = if target.contains("windows") {
        //see https://github.com/servo/rust-bindgen/issues/578
        bindings.trust_clang_mangling(false)
    } else {
        bindings
    };
    bindings = c_headers[1..].iter().fold(
        Ok(bindings),
        |acc: Result<bindgen::Builder, String>, header| {
            let c_file_path = header;
            let c_file_str = c_file_path
                .as_ref()
                .to_str()
                .ok_or_else(|| format!("Invalid unicode in path to {:?}", c_file_path.as_ref()))?;
            Ok(acc.unwrap().clang_arg("-include").clang_arg(c_file_str))
        },
    )?;

    let generated_bindings = bindings
    //        .clang_arg(format!("-target {}", target))
        .generate()
        .map_err(|_| "Failed to generate bindings".to_string())?;
    generated_bindings
        .write_to_file(output_rust)
        .map_err(|err| err.to_string())?;

    Ok(())
}

fn rust_swig_expand(source_dir: &Path, file: &Path, out_dir: &Path) -> Result<(), String> {
    let app_id = env::var("ANDROID_APPLICATION_ID")
        .expect("You must set ANDROID_APPLICATION_ID to the package name of your android application.");

    let mut registry = syntex::Registry::new();
    let swig_gen = rust_swig::Generator::new(LanguageConfig::JavaConfig(
        JavaConfig::new(
            Path::new(ANDROID_BASE_DIR)
                .join("src")
                .join("main")
                .join("java")
                .join(app_id.replace(".", "/")),
            app_id.to_owned() // not sure why it requires ownership...
        ).use_null_annotation("android.support.annotation.NonNull".into()),
    ));
    swig_gen.register(&mut registry);

    let out_file = out_dir.join(Path::new(file.parent().unwrap_or(Path::new(".")))
                                .join(file.file_stem().expect("Got invalid file (no filename)")));

    registry
        .expand(app_id.as_ref(), source_dir.join(file), out_file)
        .map_err(|err| format!("Rust-SWIG expansion failed: {}", err))
}

fn write_include_file(source_dir: &Path, swig_file: &Path) -> std::io::Result<()> {
    let rs_rel_file = Path::new(swig_file.parent().unwrap_or(Path::new(".")))
        .join(swig_file.file_stem().expect("Got invalid file (no filename)"));
    let rs_path = source_dir.join(&rs_rel_file);

    if rs_path.exists() {
        println!("Not writing {} because it exists", rs_path.display());
        return Ok(());
    }

    let mut rs_file = File::create(rs_path)?;
    rs_file.write_all(format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}\"",
                              rs_rel_file.to_string_lossy()).as_bytes())?;

    return Ok(());
}
<|endoftext|>


<commit_before>//! The MERL BRDF represents the surface's properties through data loaded from a
//! [MERL BRDF Database file](http://www.merl.com/brdf/). The BRDF itself just stores
//! the data loaded from the BRDF file while actual loading is done by the MERL material
//! when it's created.

use std::f32;
use enum_set::EnumSet;

use linalg::{self, Vector};
use film::Colorf;
use bxdf::{self, BxDF, BxDFType};

/// BRDF that uses measured data to model the surface reflectance properties.
/// The measured data is from "A Data-Driven Reflectance Model",
/// by Wojciech Matusik, Hanspeter Pfister, Matt Brand and Leonard McMillan,
/// in ACM Transactions on Graphics 22, 3(2003), 759-769
#[derive(Clone, Debug)]
pub struct Merl {
    /// Vec containing the BRDF values for various incident/exiting angles
    brdf: Vec<f32>,
    /// Number of theta_h measurements in `brdf`
    n_theta_h: usize,
    /// Number of theta_d measurements in `brdf`
    n_theta_d: usize,
    /// Number of phi_d measurements in `brdf`
    n_phi_d: usize,
}

impl Merl {
    /// Create a MERL BRDF to use data loaded from a MERL BRDF data file
    pub fn new(brdf: Vec<f32>, n_theta_h: usize, n_theta_d: usize, n_phi_d: usize) -> Merl {
        Merl { brdf: brdf, n_theta_h: n_theta_h, n_theta_d: n_theta_d, n_phi_d: n_phi_d }
    }
    /// Re-map values from an angular value to the index in the MERL data table
    fn map_index(val: f32, max: f32, n_vals: usize) -> usize {
        linalg::clamp((val / max * n_vals as f32) as usize, 0, n_vals - 1)
    }
}

impl BxDF for Merl {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Reflection);
        e
    }
    fn eval(&self, w_oi: &Vector, w_ii: &Vector) -> Colorf {
        // Find the half-vector and transform into the half angle coordinate system used by MERL
        // BRDF files
        let mut w_o = *w_oi;
        let mut w_i = *w_ii;
        let mut w_h = w_o + w_i;
        if w_h.z < 0.0 {
            w_o = -w_o;
            w_i = -w_i;
            w_h = -w_h;
        }
        if w_h.length_sqr() == 0.0 {
            return Colorf::black();
        }

        let w_h = w_h.normalized();
        // Directly compute the rows of the matrix performing the rotation of w_h to (0, 0, 1)
        let theta_h = linalg::spherical_theta(&w_h);
        let cos_phi_h = bxdf::cos_phi(&w_h);
        let sin_phi_h = bxdf::sin_phi(&w_h);
        let cos_theta_h = bxdf::cos_theta(&w_h);
        let sin_theta_h = bxdf::sin_theta(&w_h);
        let w_hx = Vector::new(cos_phi_h * cos_theta_h, sin_phi_h * cos_theta_h, -sin_theta_h);
        let w_hy = Vector::new(-sin_phi_h, cos_phi_h, 0.0);
        let w_d = Vector::new(linalg::dot(&w_i, &w_hx), linalg::dot(&w_i, &w_hy), linalg::dot(&w_i, &w_h));
        let theta_d = linalg::spherical_theta(&w_d);
        // Wrap phi_d if needed to keep it in range
        let phi_d = match linalg::spherical_phi(&w_d) {
            d if d > f32::consts::PI => d - f32::consts::PI,
            d => d,
        };
        let theta_h_idx = Merl::map_index(f32::sqrt(f32::max(0.0, 2.0 * theta_h / f32::consts::PI)), 1.0, self.n_theta_h);
        let theta_d_idx = Merl::map_index(theta_d, f32::consts::PI / 2.0, self.n_theta_d);
        let phi_d_idx = Merl::map_index(phi_d, f32::consts::PI, self.n_phi_d);
        let i = phi_d_idx + self.n_phi_d * (theta_d_idx + theta_h_idx * self.n_theta_d);
        assert!(i < self.brdf.len());
        Colorf::new(self.brdf[3 * i], self.brdf[3 * i + 1], self.brdf[3 * i + 2])
    }
}

<commit_msg>Remove unused variable<commit_after>//! The MERL BRDF represents the surface's properties through data loaded from a
//! [MERL BRDF Database file](http://www.merl.com/brdf/). The BRDF itself just stores
//! the data loaded from the BRDF file while actual loading is done by the MERL material
//! when it's created.

use std::f32;
use enum_set::EnumSet;

use linalg::{self, Vector};
use film::Colorf;
use bxdf::{self, BxDF, BxDFType};

/// BRDF that uses measured data to model the surface reflectance properties.
/// The measured data is from "A Data-Driven Reflectance Model",
/// by Wojciech Matusik, Hanspeter Pfister, Matt Brand and Leonard McMillan,
/// in ACM Transactions on Graphics 22, 3(2003), 759-769
#[derive(Clone, Debug)]
pub struct Merl {
    /// Vec containing the BRDF values for various incident/exiting angles
    brdf: Vec<f32>,
    /// Number of theta_h measurements in `brdf`
    n_theta_h: usize,
    /// Number of theta_d measurements in `brdf`
    n_theta_d: usize,
    /// Number of phi_d measurements in `brdf`
    n_phi_d: usize,
}

impl Merl {
    /// Create a MERL BRDF to use data loaded from a MERL BRDF data file
    pub fn new(brdf: Vec<f32>, n_theta_h: usize, n_theta_d: usize, n_phi_d: usize) -> Merl {
        Merl { brdf: brdf, n_theta_h: n_theta_h, n_theta_d: n_theta_d, n_phi_d: n_phi_d }
    }
    /// Re-map values from an angular value to the index in the MERL data table
    fn map_index(val: f32, max: f32, n_vals: usize) -> usize {
        linalg::clamp((val / max * n_vals as f32) as usize, 0, n_vals - 1)
    }
}

impl BxDF for Merl {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Reflection);
        e
    }
    fn eval(&self, w_oi: &Vector, w_ii: &Vector) -> Colorf {
        // Find the half-vector and transform into the half angle coordinate system used by MERL
        // BRDF files
        let mut w_i = *w_ii;
        let mut w_h = *w_oi + w_i;
        if w_h.z < 0.0 {
            w_i = -w_i;
            w_h = -w_h;
        }
        if w_h.length_sqr() == 0.0 {
            return Colorf::black();
        }

        let w_h = w_h.normalized();
        // Directly compute the rows of the matrix performing the rotation of w_h to (0, 0, 1)
        let theta_h = linalg::spherical_theta(&w_h);
        let cos_phi_h = bxdf::cos_phi(&w_h);
        let sin_phi_h = bxdf::sin_phi(&w_h);
        let cos_theta_h = bxdf::cos_theta(&w_h);
        let sin_theta_h = bxdf::sin_theta(&w_h);
        let w_hx = Vector::new(cos_phi_h * cos_theta_h, sin_phi_h * cos_theta_h, -sin_theta_h);
        let w_hy = Vector::new(-sin_phi_h, cos_phi_h, 0.0);
        let w_d = Vector::new(linalg::dot(&w_i, &w_hx), linalg::dot(&w_i, &w_hy), linalg::dot(&w_i, &w_h));
        let theta_d = linalg::spherical_theta(&w_d);
        // Wrap phi_d if needed to keep it in range
        let phi_d = match linalg::spherical_phi(&w_d) {
            d if d > f32::consts::PI => d - f32::consts::PI,
            d => d,
        };
        let theta_h_idx = Merl::map_index(f32::sqrt(f32::max(0.0, 2.0 * theta_h / f32::consts::PI)), 1.0, self.n_theta_h);
        let theta_d_idx = Merl::map_index(theta_d, f32::consts::PI / 2.0, self.n_theta_d);
        let phi_d_idx = Merl::map_index(phi_d, f32::consts::PI, self.n_phi_d);
        let i = phi_d_idx + self.n_phi_d * (theta_d_idx + theta_h_idx * self.n_theta_d);
        assert!(i < self.brdf.len());
        Colorf::new(self.brdf[3 * i], self.brdf[3 * i + 1], self.brdf[3 * i + 2])
    }
}

<|endoftext|>