<commit_before>use core::cell::Cell;
use core::mem;
use core::intrinsics;
use common::take_cell::TakeCell;
use pm;
use nvic;

use helpers::*;

/// Memory registers for a DMA channel. Section 16.6.1 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct DMARegisters {
    memory_address:           usize,
    peripheral_select:        usize,
    transfer_counter:         usize,
    memory_address_reload:    usize,
    transfer_counter_reload:  usize,
    control:                  usize,
    mode:                     usize,
    status:                   usize,
    interrupt_enable:         usize,
    interrupt_disable:        usize,
    interrupt_mask:           usize,
    interrupt_status:         usize,
    version:                  usize,
    _unused:                  [usize; 3]
}

/// The PDCA's base addresses in memory (Section 7.1 of manual)
pub const DMA_BASE_ADDR : usize = 0x400A2000;

/// The number of bytes between each memory mapped DMA Channel (Section 16.6.1)
pub const DMA_CHANNEL_SIZE : usize = 0x40;

/// Shared counter that Keeps track of how many DMA channels are currently
/// active.
static mut NUM_ENABLED: usize = 0;

/// The DMA channel number. Each channel transfers data between memory and a
/// particular peripheral function (e.g., SPI read or SPI write, but not both
/// simultaneously). There are 16 available channels (Section 16.7)
#[derive(Copy,Clone)]
pub enum DMAChannelNum {
    // Relies on the fact that assigns values 0-15 to each constructor in order
    DMAChannel00 = 0,
    DMAChannel01 = 1,
    DMAChannel02 = 2,
    DMAChannel03 = 3,
    DMAChannel04 = 4,
    DMAChannel05 = 5,
    DMAChannel06 = 6,
    DMAChannel07 = 7,
    DMAChannel08 = 8,
    DMAChannel09 = 9,
    DMAChannel10 = 10,
    DMAChannel11 = 11,
    DMAChannel12 = 12,
    DMAChannel13 = 13,
    DMAChannel14 = 14,
    DMAChannel15 = 15
}

/// The peripheral function a channel is assigned to (Section 16.7)
/// *_RX means transfer data from peripheral to memory, *_TX means transfer data
/// from memory to peripheral.
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum DMAPeripheral {
    USART0_RX      = 0,
    USART1_RX      = 1,
    USART2_RX      = 2,
    USART3_RX      = 3,
    SPI_RX         = 4,
    TWIM0_RX       = 5,
    TWIM1_RX       = 6,
    TWIM2_RX       = 7,
    TWIM3_RX       = 8,
    TWIS0_RX       = 9,
    TWIS1_RX       = 10,
    ADCIFE_RX      = 11,
    CATB_RX        = 12,
    IISC_CH0_RX    = 14,
    IISC_CH1_RX    = 15,
    PARC_RX        = 16,
    AESA_RX        = 17,
    USART0_TX      = 18,
    USART1_TX      = 19,
    USART2_TX      = 20,
    USART3_TX      = 21,
    SPI_TX         = 22,
    TWIM0_TX       = 23,
    TWIM1_TX       = 24,
    TWIM2_TX       = 25,
    TWIM3_TX       = 26,
    TWIS0_TX       = 27,
    TWIS1_TX       = 28,
    ADCIFE_TX      = 29,
    CATB_TX        = 30,
    ABDACB_SDR0_TX = 31,
    ABDACB_SDR1_TX = 32,
    IISC_CH0_TX    = 33,
    IISC_CH1_TX    = 34,
    DACC_TX        = 35,
    AESA_TX        = 36,
    LCDCA_ACMDR_TX = 37,
    LCDCA_ABMDR_TX = 38
}

pub static mut DMAChannels : [DMAChannel; 16] = [
    DMAChannel::new(DMAChannelNum::DMAChannel00, nvic::NvicIdx::PDCA0),
    DMAChannel::new(DMAChannelNum::DMAChannel01, nvic::NvicIdx::PDCA1),
    DMAChannel::new(DMAChannelNum::DMAChannel02, nvic::NvicIdx::PDCA2),
    DMAChannel::new(DMAChannelNum::DMAChannel03, nvic::NvicIdx::PDCA3),
    DMAChannel::new(DMAChannelNum::DMAChannel04, nvic::NvicIdx::PDCA4),
    DMAChannel::new(DMAChannelNum::DMAChannel05, nvic::NvicIdx::PDCA5),
    DMAChannel::new(DMAChannelNum::DMAChannel06, nvic::NvicIdx::PDCA6),
    DMAChannel::new(DMAChannelNum::DMAChannel07, nvic::NvicIdx::PDCA7),
    DMAChannel::new(DMAChannelNum::DMAChannel08, nvic::NvicIdx::PDCA8),
    DMAChannel::new(DMAChannelNum::DMAChannel09, nvic::NvicIdx::PDCA9),
    DMAChannel::new(DMAChannelNum::DMAChannel10, nvic::NvicIdx::PDCA10),
    DMAChannel::new(DMAChannelNum::DMAChannel11, nvic::NvicIdx::PDCA11),
    DMAChannel::new(DMAChannelNum::DMAChannel12, nvic::NvicIdx::PDCA12),
    DMAChannel::new(DMAChannelNum::DMAChannel13, nvic::NvicIdx::PDCA13),
    DMAChannel::new(DMAChannelNum::DMAChannel14, nvic::NvicIdx::PDCA14),
    DMAChannel::new(DMAChannelNum::DMAChannel15, nvic::NvicIdx::PDCA15),
];

pub struct DMAChannel {
    registers: *mut DMARegisters,
    nvic: nvic::NvicIdx,
    pub client: Option<&'static mut DMAClient>,
    enabled: Cell<bool>,
    buffer: TakeCell<&'static mut [u8]>
}

pub trait DMAClient {
    fn xfer_done(&mut self, pid: usize);
}

impl DMAChannel {
    const fn new(channel: DMAChannelNum, nvic: nvic::NvicIdx) -> DMAChannel {
        DMAChannel {
            registers: (DMA_BASE_ADDR + (channel as usize) * DMA_CHANNEL_SIZE)
                    as *mut DMARegisters,
            nvic: nvic,
            client: None,
            enabled: Cell::new(false),
            buffer: TakeCell::empty()
        }
    }

    pub fn enable(&self) {
        unsafe {
            pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
            pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
        }
        if !self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xadd(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.interrupt_disable, 0xffffffff);

            unsafe { nvic::enable(self.nvic) };

            self.enabled.set(true);
        }
    }

    pub fn disable(&self) {
        if self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xsub(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::disable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::disable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.control, 0x2);
            self.enabled.set(false);
            unsafe {
                nvic::disable(self.nvic);
            }
        }
    }

    pub fn handle_interrupt(&mut self) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        let channel : usize = volatile_load(&registers.peripheral_select);

        self.client.as_mut().map(|client| {
            client.xfer_done(channel);
        });
    }

    pub fn start_xfer(&self) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_store(&mut registers.control, 0x1);
    }

    pub fn prepare_xfer(&self, pid: DMAPeripheral,
                        buf: &'static mut [u8],
                        mut len: usize) {
        // TODO(alevy): take care of zero length case
        if len > buf.len() {
            len = buf.len();
        }

        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_store(&mut registers.peripheral_select, pid as usize);
        volatile_store(&mut registers.memory_address_reload,
                       &buf[0] as *const u8 as usize);
        volatile_store(&mut registers.transfer_counter_reload, len);

        volatile_store(&mut registers.interrupt_enable, 1 << 1);

        // Store the buffer reference in the TakeCell so it can be returned to
        // the caller in `handle_interrupt`
        self.buffer.replace(buf);
    }

    pub fn do_xfer(&self, pid: DMAPeripheral,
                       buf: &'static mut [u8],
                       len: usize) {
        self.prepare_xfer(pid, buf, len);
        self.start_xfer();
    }

    /// Aborts any current transactions and returns the buffer used in the
    /// transaction.
    pub fn abort_xfer(&self) -> Option<&'static mut [u8]> {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_store(&mut registers.interrupt_disable, !0);

        // Reset counter
        volatile_store(&mut registers.transfer_counter, 0);

        self.buffer.take()
    }

    pub fn transfer_counter(&self) -> usize {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_load(&registers.transfer_counter)
    }
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[0].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA0);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA0);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[1].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA1);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA1);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[2].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA2);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA2);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[3].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA3);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA3);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[4].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA4);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA4);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[5].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA5);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA4);
}

<commit_msg>SAM4L: Another DMA interrupt handler bug<commit_after>use core::cell::Cell;
use core::mem;
use core::intrinsics;
use common::take_cell::TakeCell;
use pm;
use nvic;

use helpers::*;

/// Memory registers for a DMA channel. Section 16.6.1 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct DMARegisters {
    memory_address:           usize,
    peripheral_select:        usize,
    transfer_counter:         usize,
    memory_address_reload:    usize,
    transfer_counter_reload:  usize,
    control:                  usize,
    mode:                     usize,
    status:                   usize,
    interrupt_enable:         usize,
    interrupt_disable:        usize,
    interrupt_mask:           usize,
    interrupt_status:         usize,
    version:                  usize,
    _unused:                  [usize; 3]
}

/// The PDCA's base addresses in memory (Section 7.1 of manual)
pub const DMA_BASE_ADDR : usize = 0x400A2000;

/// The number of bytes between each memory mapped DMA Channel (Section 16.6.1)
pub const DMA_CHANNEL_SIZE : usize = 0x40;

/// Shared counter that Keeps track of how many DMA channels are currently
/// active.
static mut NUM_ENABLED: usize = 0;

/// The DMA channel number. Each channel transfers data between memory and a
/// particular peripheral function (e.g., SPI read or SPI write, but not both
/// simultaneously). There are 16 available channels (Section 16.7)
#[derive(Copy,Clone)]
pub enum DMAChannelNum {
    // Relies on the fact that assigns values 0-15 to each constructor in order
    DMAChannel00 = 0,
    DMAChannel01 = 1,
    DMAChannel02 = 2,
    DMAChannel03 = 3,
    DMAChannel04 = 4,
    DMAChannel05 = 5,
    DMAChannel06 = 6,
    DMAChannel07 = 7,
    DMAChannel08 = 8,
    DMAChannel09 = 9,
    DMAChannel10 = 10,
    DMAChannel11 = 11,
    DMAChannel12 = 12,
    DMAChannel13 = 13,
    DMAChannel14 = 14,
    DMAChannel15 = 15
}

/// The peripheral function a channel is assigned to (Section 16.7)
/// *_RX means transfer data from peripheral to memory, *_TX means transfer data
/// from memory to peripheral.
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum DMAPeripheral {
    USART0_RX      = 0,
    USART1_RX      = 1,
    USART2_RX      = 2,
    USART3_RX      = 3,
    SPI_RX         = 4,
    TWIM0_RX       = 5,
    TWIM1_RX       = 6,
    TWIM2_RX       = 7,
    TWIM3_RX       = 8,
    TWIS0_RX       = 9,
    TWIS1_RX       = 10,
    ADCIFE_RX      = 11,
    CATB_RX        = 12,
    IISC_CH0_RX    = 14,
    IISC_CH1_RX    = 15,
    PARC_RX        = 16,
    AESA_RX        = 17,
    USART0_TX      = 18,
    USART1_TX      = 19,
    USART2_TX      = 20,
    USART3_TX      = 21,
    SPI_TX         = 22,
    TWIM0_TX       = 23,
    TWIM1_TX       = 24,
    TWIM2_TX       = 25,
    TWIM3_TX       = 26,
    TWIS0_TX       = 27,
    TWIS1_TX       = 28,
    ADCIFE_TX      = 29,
    CATB_TX        = 30,
    ABDACB_SDR0_TX = 31,
    ABDACB_SDR1_TX = 32,
    IISC_CH0_TX    = 33,
    IISC_CH1_TX    = 34,
    DACC_TX        = 35,
    AESA_TX        = 36,
    LCDCA_ACMDR_TX = 37,
    LCDCA_ABMDR_TX = 38
}

pub static mut DMAChannels : [DMAChannel; 16] = [
    DMAChannel::new(DMAChannelNum::DMAChannel00, nvic::NvicIdx::PDCA0),
    DMAChannel::new(DMAChannelNum::DMAChannel01, nvic::NvicIdx::PDCA1),
    DMAChannel::new(DMAChannelNum::DMAChannel02, nvic::NvicIdx::PDCA2),
    DMAChannel::new(DMAChannelNum::DMAChannel03, nvic::NvicIdx::PDCA3),
    DMAChannel::new(DMAChannelNum::DMAChannel04, nvic::NvicIdx::PDCA4),
    DMAChannel::new(DMAChannelNum::DMAChannel05, nvic::NvicIdx::PDCA5),
    DMAChannel::new(DMAChannelNum::DMAChannel06, nvic::NvicIdx::PDCA6),
    DMAChannel::new(DMAChannelNum::DMAChannel07, nvic::NvicIdx::PDCA7),
    DMAChannel::new(DMAChannelNum::DMAChannel08, nvic::NvicIdx::PDCA8),
    DMAChannel::new(DMAChannelNum::DMAChannel09, nvic::NvicIdx::PDCA9),
    DMAChannel::new(DMAChannelNum::DMAChannel10, nvic::NvicIdx::PDCA10),
    DMAChannel::new(DMAChannelNum::DMAChannel11, nvic::NvicIdx::PDCA11),
    DMAChannel::new(DMAChannelNum::DMAChannel12, nvic::NvicIdx::PDCA12),
    DMAChannel::new(DMAChannelNum::DMAChannel13, nvic::NvicIdx::PDCA13),
    DMAChannel::new(DMAChannelNum::DMAChannel14, nvic::NvicIdx::PDCA14),
    DMAChannel::new(DMAChannelNum::DMAChannel15, nvic::NvicIdx::PDCA15),
];

pub struct DMAChannel {
    registers: *mut DMARegisters,
    nvic: nvic::NvicIdx,
    pub client: Option<&'static mut DMAClient>,
    enabled: Cell<bool>,
    buffer: TakeCell<&'static mut [u8]>
}

pub trait DMAClient {
    fn xfer_done(&mut self, pid: usize);
}

impl DMAChannel {
    const fn new(channel: DMAChannelNum, nvic: nvic::NvicIdx) -> DMAChannel {
        DMAChannel {
            registers: (DMA_BASE_ADDR + (channel as usize) * DMA_CHANNEL_SIZE)
                    as *mut DMARegisters,
            nvic: nvic,
            client: None,
            enabled: Cell::new(false),
            buffer: TakeCell::empty()
        }
    }

    pub fn enable(&self) {
        unsafe {
            pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
            pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
        }
        if !self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xadd(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.interrupt_disable, 0xffffffff);

            unsafe { nvic::enable(self.nvic) };

            self.enabled.set(true);
        }
    }

    pub fn disable(&self) {
        if self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xsub(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::disable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::disable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.control, 0x2);
            self.enabled.set(false);
            unsafe {
                nvic::disable(self.nvic);
            }
        }
    }

    pub fn handle_interrupt(&mut self) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        let channel : usize = volatile_load(&registers.peripheral_select);

        self.client.as_mut().map(|client| {
            client.xfer_done(channel);
        });
    }

    pub fn start_xfer(&self) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_store(&mut registers.control, 0x1);
    }

    pub fn prepare_xfer(&self, pid: DMAPeripheral,
                        buf: &'static mut [u8],
                        mut len: usize) {
        // TODO(alevy): take care of zero length case
        if len > buf.len() {
            len = buf.len();
        }

        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_store(&mut registers.peripheral_select, pid as usize);
        volatile_store(&mut registers.memory_address_reload,
                       &buf[0] as *const u8 as usize);
        volatile_store(&mut registers.transfer_counter_reload, len);

        volatile_store(&mut registers.interrupt_enable, 1 << 1);

        // Store the buffer reference in the TakeCell so it can be returned to
        // the caller in `handle_interrupt`
        self.buffer.replace(buf);
    }

    pub fn do_xfer(&self, pid: DMAPeripheral,
                       buf: &'static mut [u8],
                       len: usize) {
        self.prepare_xfer(pid, buf, len);
        self.start_xfer();
    }

    /// Aborts any current transactions and returns the buffer used in the
    /// transaction.
    pub fn abort_xfer(&self) -> Option<&'static mut [u8]> {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_store(&mut registers.interrupt_disable, !0);

        // Reset counter
        volatile_store(&mut registers.transfer_counter, 0);

        self.buffer.take()
    }

    pub fn transfer_counter(&self) -> usize {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        volatile_load(&registers.transfer_counter)
    }
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[0].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA0);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA0);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[1].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA1);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA1);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[2].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA2);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA2);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[3].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA3);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA3);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[4].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA4);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA4);
}

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

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[5].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA5);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA5);
}

<|endoftext|>


<commit_before>use {Timer, Color};
use serde_json::{to_writer, Result};
use std::io::Write;
use analysis::{state_helper, delta};
use time_formatter::{Delta, TimeFormatter, Accuracy};

#[derive(Default)]
pub struct Component {
    settings: Settings,
}

#[derive(Serialize, Deserialize)]
pub struct Settings {
    pub comparison_override: Option<String>,
    pub drop_decimals: bool,
    pub accuracy: Accuracy,
}

impl Default for Settings {
    fn default() -> Self {
        Self {
            comparison_override: None,
            drop_decimals: true,
            accuracy: Accuracy::Tenths,
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct State {
    pub text: String,
    pub time: String,
    pub color: Color,
}

impl State {
    pub fn write_json<W>(&self, mut writer: W) -> Result<()>
        where W: Write
    {
        to_writer(&mut writer, self)
    }
}

impl Component {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn with_settings(settings: Settings) -> Self {
        Self {
            settings,
            ..Default::default()
        }
    }

    pub fn settings_mut(&mut self) -> &mut Settings {
        &mut self.settings
    }

    pub fn state(&self, timer: &Timer) -> State {
        let comparison = self.settings
            .comparison_override
            .as_ref()
            .and_then(|c| timer.run().comparisons().find(|&rc| c == rc))
            .unwrap_or_else(|| timer.current_comparison());

        let (delta, use_live_delta) = delta::calculate(timer, comparison);

        let mut index = timer.current_split_index();
        if use_live_delta {
            index -= 1;
        }
        let color = if index >= 0 {
            state_helper::split_color(timer,
                                      delta,
                                      index as usize,
                                      true,
                                      false,
                                      comparison,
                                      timer.current_timing_method())
        } else {
            Color::Default
        };

        let text = if let Some(comparison) = self.settings.comparison_override.as_ref() {
            format!("Delta ({})", comparison)
        } else {
            String::from("Delta")
        };

        State {
            text,
            time: Delta::custom(self.settings.drop_decimals, self.settings.accuracy)
                .format(delta)
                .to_string(),
            color,
        }
    }
}
<commit_msg>Fix Text of Delta Component<commit_after>use {Timer, Color};
use serde_json::{to_writer, Result};
use std::io::Write;
use analysis::{state_helper, delta};
use time_formatter::{Delta, TimeFormatter, Accuracy};

#[derive(Default)]
pub struct Component {
    settings: Settings,
}

#[derive(Serialize, Deserialize)]
pub struct Settings {
    pub comparison_override: Option<String>,
    pub drop_decimals: bool,
    pub accuracy: Accuracy,
}

impl Default for Settings {
    fn default() -> Self {
        Self {
            comparison_override: None,
            drop_decimals: true,
            accuracy: Accuracy::Tenths,
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct State {
    pub text: String,
    pub time: String,
    pub color: Color,
}

impl State {
    pub fn write_json<W>(&self, mut writer: W) -> Result<()>
        where W: Write
    {
        to_writer(&mut writer, self)
    }
}

impl Component {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn with_settings(settings: Settings) -> Self {
        Self {
            settings,
            ..Default::default()
        }
    }

    pub fn settings_mut(&mut self) -> &mut Settings {
        &mut self.settings
    }

    pub fn state(&self, timer: &Timer) -> State {
        let comparison = self.settings
            .comparison_override
            .as_ref()
            .and_then(|c| timer.run().comparisons().find(|&rc| c == rc))
            .unwrap_or_else(|| timer.current_comparison());

        let (delta, use_live_delta) = delta::calculate(timer, comparison);

        let mut index = timer.current_split_index();
        if use_live_delta {
            index -= 1;
        }
        let color = if index >= 0 {
            state_helper::split_color(timer,
                                      delta,
                                      index as usize,
                                      true,
                                      false,
                                      comparison,
                                      timer.current_timing_method())
        } else {
            Color::Default
        };

        State {
            text: String::from(comparison),
            time: Delta::custom(self.settings.drop_decimals, self.settings.accuracy)
                .format(delta)
                .to_string(),
            color,
        }
    }
}
<|endoftext|>


<commit_before>//! "Dummy" environment for testing wasm translation.

use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
                        FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;

/// Compute a `ir::ExternalName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::ExternalName {
    ir::ExternalName::new(format!("wasm_0x{:x}", func_index))
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: Vec<Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: Vec<ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FunctionIndex>,
}

impl DummyModuleInfo {
    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: Vec::new(),
            function_bodies: Vec::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,
}

impl DummyEnvironment {
    /// Allocates the data structures with default flags.
    pub fn default() -> Self {
        Self::with_flags(settings::Flags::new(&settings::builder()))
    }

    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_flags(flags),
            trans: FuncTranslator::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The FuncEnvironment implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
        GlobalValue::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        func.create_heap(ir::HeapData {
            base: ir::HeapBase::ReservedReg,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.mod_info.signatures[index].clone())
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData { name, signature })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> ir::Inst {
        pos.ins().call_indirect(sig_ref, callee, call_args)
    }

    fn translate_grow_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }

    fn translate_current_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }
}

impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
    fn get_func_name(&self, func_index: FunctionIndex) -> ir::ExternalName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info.imported_funcs.push((
            String::from(module),
            String::from(field),
        ));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: Vec<FunctionIndex>,
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export(&mut self, func_index: FunctionIndex, name: &'data str) {
        self.info.functions[func_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index].export_names.push(
            String::from(name),
        );
    }

    fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_start_func(&mut self, func_index: FunctionIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
        let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
        let name = get_func_name(function_index);
        let sig = self.get_signature(self.get_func_type(function_index))
            .clone();
        let mut func = ir::Function::with_name_signature(name, sig);
        {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)
                .map_err(|e| String::from(e.description()))?;
        }
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<commit_msg>wasm: change to new externalname api<commit_after>//! "Dummy" environment for testing wasm translation.

use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
                        FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;

/// Compute a `ir::ExternalName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::ExternalName {
    ir::ExternalName::user(0, func_index as u32)
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: Vec<Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: Vec<ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FunctionIndex>,
}

impl DummyModuleInfo {
    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: Vec::new(),
            function_bodies: Vec::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,
}

impl DummyEnvironment {
    /// Allocates the data structures with default flags.
    pub fn default() -> Self {
        Self::with_flags(settings::Flags::new(&settings::builder()))
    }

    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_flags(flags),
            trans: FuncTranslator::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The FuncEnvironment implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
        GlobalValue::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        func.create_heap(ir::HeapData {
            base: ir::HeapBase::ReservedReg,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.mod_info.signatures[index].clone())
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData { name, signature })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> ir::Inst {
        pos.ins().call_indirect(sig_ref, callee, call_args)
    }

    fn translate_grow_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }

    fn translate_current_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }
}

impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
    fn get_func_name(&self, func_index: FunctionIndex) -> ir::ExternalName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info.imported_funcs.push((
            String::from(module),
            String::from(field),
        ));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: Vec<FunctionIndex>,
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export(&mut self, func_index: FunctionIndex, name: &'data str) {
        self.info.functions[func_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index].export_names.push(
            String::from(name),
        );
    }

    fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_start_func(&mut self, func_index: FunctionIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
        let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
        let name = get_func_name(function_index);
        let sig = self.get_signature(self.get_func_type(function_index))
            .clone();
        let mut func = ir::Function::with_name_signature(name, sig);
        {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)
                .map_err(|e| String::from(e.description()))?;
        }
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Representations of C types and arrays thereof.
//!
//! These are used to describe the types of the arguments and results of
//! functions. When we construct a CIF (“Call InterFace”),
//! we provide a sequence of argument types and a result type, and
//! libffi uses this to figure out how to set up a call to a function
//! with those types.

use libc;
use std::fmt;
use std::mem;
use std::ptr;

use crate::low;

use super::util::Unique;

// Internally we represent types and type arrays using raw pointers,
// since this is what libffi understands. Below we wrap them with
// types that implement Drop and Clone.

type Type_ = *mut low::ffi_type;
type TypeArray_ = *mut Type_;

// Informal indication that the object should be considered owned by
// the given reference.
type Owned<T> = T;

/// Represents a single C type.
///
/// # Example
///
/// Suppose we have a C struct:
///
/// ```c
/// struct my_struct {
///     uint16_t f1;
///     uint64_t f2;
/// };
/// ```
///
/// To pass the struct by value via libffi, we need to construct a
/// `Type` object describing its layout:
///
/// ```
/// use libffi::middle::Type;
///
/// let my_struct = Type::structure(vec![
///     Type::u64(),
///     Type::u16(),
/// ]);
/// ```
pub struct Type(Unique<low::ffi_type>);

/// Represents a sequence of C types.
///
/// This can be used to construct a struct type or as the arguments
/// when creating a [`Cif`](struct.Cif.html).
pub struct TypeArray(Unique<*mut low::ffi_type>);

impl fmt::Debug for Type {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("Type({:?})", *self.0))
    }
}

impl fmt::Debug for TypeArray {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("TypeArray({:?})", *self.0))
    }
}

/// Computes the length of a raw `TypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: TypeArray_) -> usize {
    let mut count = 0;
    while !(*array).is_null() {
        count += 1;
        array = array.offset(1);
    }
    count
}

/// Creates an empty `TypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<TypeArray_> {
    let array = libc::malloc((len + 1) * mem::size_of::<Type_>()) as TypeArray_;
    assert!(
        !array.is_null(),
        "ffi_type_array_create_empty: out of memory"
    );
    *array.add(len) = ptr::null_mut::<low::ffi_type>() as Type_;
    array
}

/// Creates a null-terminated array of Type_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: I) -> Owned<TypeArray_>
where
    I: ExactSizeIterator<Item = Type>,
{
    let size = elements.len();
    let new = ffi_type_array_create_empty(size);
    for (i, element) in elements.enumerate() {
        *new.add(i) = *element.0;
        forget(element);
    }

    new
}

/// Creates a struct type from a raw array of element types.
unsafe fn ffi_type_struct_create_raw(elements: Owned<TypeArray_>) -> Owned<Type_> {
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as Type_;
    assert!(!new.is_null(), "ffi_type_struct_create_raw: out of memory");

    (*new).size = 0;
    (*new).alignment = 0;
    (*new).type_ = low::type_tag::STRUCT;
    (*new).elements = elements;

    new
}

/// Creates a struct `ffi_type` with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: I) -> Owned<Type_>
where
    I: ExactSizeIterator<Item = Type>,
{
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

/// Makes a copy of a type array.
unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
    let size = ffi_type_array_len(old);
    let new = ffi_type_array_create_empty(size);

    for i in 0..size {
        *new.add(i) = ffi_type_clone(*old.add(i));
    }

    new
}

/// Makes a copy of a type.
unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
    if (*old).type_ == low::type_tag::STRUCT {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys a `TypeArray_` and all of its elements.
unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys a `Type_` if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
    if (*victim).type_ == low::type_tag::STRUCT {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for Type {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(*self.0) }
    }
}

impl Drop for TypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(*self.0) }
    }
}

impl Clone for Type {
    fn clone(&self) -> Self {
        Type(unsafe { Unique::new(ffi_type_clone(*self.0)) })
    }
}

impl Clone for TypeArray {
    fn clone(&self) -> Self {
        TypeArray(unsafe { Unique::new(ffi_type_array_clone(*self.0)) })
    }
}

macro_rules! match_size_signed {
    ( $name:ident ) => {
        match mem::size_of::<libc::$name>() {
            1 => Self::i8(),
            2 => Self::i16(),
            4 => Self::i32(),
            8 => Self::i64(),
            _ => panic!("Strange size for C type"),
        }
    };
}

macro_rules! match_size_unsigned {
    ( $name:ident ) => {
        match mem::size_of::<libc::$name>() {
            1 => Self::u8(),
            2 => Self::u16(),
            4 => Self::u32(),
            8 => Self::u64(),
            _ => panic!("Strange size for C type"),
        }
    };
}

impl Type {
    /// Returns the representation of the C `void` type.
    ///
    /// This is used only for the return type of a CIF, not for an
    /// argument or struct member.
    pub fn void() -> Self {
        Type(unsafe { Unique::new(&mut low::types::void) })
    }

    /// Returns the unsigned 8-bit numeric type.
    pub fn u8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint8) })
    }

    /// Returns the signed 8-bit numeric type.
    pub fn i8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint8) })
    }

    /// Returns the unsigned 16-bit numeric type.
    pub fn u16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint16) })
    }

    /// Returns the signed 16-bit numeric type.
    pub fn i16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint16) })
    }

    /// Returns the unsigned 32-bit numeric type.
    pub fn u32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint32) })
    }

    /// Returns the signed 32-bit numeric type.
    pub fn i32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint32) })
    }

    /// Returns the unsigned 64-bit numeric type.
    pub fn u64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint64) })
    }

    /// Returns the signed 64-bit numeric type.
    pub fn i64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint64) })
    }

    #[cfg(target_pointer_width = "16")]
    /// Returns the C equivalent of Rust `usize` (`u16`).
    pub fn usize() -> Self {
        Self::u16()
    }

    #[cfg(target_pointer_width = "16")]
    /// Returns the C equivalent of Rust `isize` (`i16`).
    pub fn isize() -> Self {
        Self::i16()
    }

    #[cfg(target_pointer_width = "32")]
    /// Returns the C equivalent of Rust `usize` (`u32`).
    pub fn usize() -> Self {
        Self::u32()
    }

    #[cfg(target_pointer_width = "32")]
    /// Returns the C equivalent of Rust `isize` (`i32`).
    pub fn isize() -> Self {
        Self::i32()
    }

    #[cfg(target_pointer_width = "64")]
    /// Returns the C equivalent of Rust `usize` (`u64`).
    pub fn usize() -> Self {
        Self::u64()
    }

    #[cfg(target_pointer_width = "64")]
    /// Returns the C equivalent of Rust `isize` (`i64`).
    pub fn isize() -> Self {
        Self::i64()
    }

    /// Returns the C `signed char` type.
    pub fn c_schar() -> Self {
        match_size_signed!(c_schar)
    }

    /// Returns the C `unsigned char` type.
    pub fn c_uchar() -> Self {
        match_size_unsigned!(c_uchar)
    }

    /// Returns the C `short` type.
    pub fn c_short() -> Self {
        match_size_signed!(c_short)
    }

    /// Returns the C `unsigned short` type.
    pub fn c_ushort() -> Self {
        match_size_unsigned!(c_ushort)
    }

    /// Returns the C `int` type.
    pub fn c_int() -> Self {
        match_size_signed!(c_int)
    }

    /// Returns the C `unsigned int` type.
    pub fn c_uint() -> Self {
        match_size_unsigned!(c_uint)
    }

    /// Returns the C `long` type.
    pub fn c_long() -> Self {
        match_size_signed!(c_long)
    }

    /// Returns the C `unsigned long` type.
    pub fn c_ulong() -> Self {
        match_size_unsigned!(c_ulong)
    }

    /// Returns the C `longlong` type.
    pub fn c_longlong() -> Self {
        match_size_signed!(c_longlong)
    }

    /// Returns the C `unsigned longlong` type.
    pub fn c_ulonglong() -> Self {
        match_size_unsigned!(c_ulonglong)
    }

    /// Returns the C `float` (32-bit floating point) type.
    pub fn f32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::float) })
    }

    /// Returns the C `double` (64-bit floating point) type.
    pub fn f64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::double) })
    }

    /// Returns the C `void*` type, for passing any kind of pointer.
    pub fn pointer() -> Self {
        Type(unsafe { Unique::new(&mut low::types::pointer) })
    }

    /// Returns the C `long double` (extended-precision floating point) type.
    #[cfg(not(all(target_arch = "arm")))]
    pub fn longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::longdouble) })
    }

    /// Returns the C `_Complex float` type.
    ///
    /// This item is enabled by `#[cfg(feature = "complex")]`.
    #[cfg(feature = "complex")]
    pub fn c32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_float) })
    }

    /// Returns the C `_Complex double` type.
    ///
    /// This item is enabled by `#[cfg(feature = "complex")]`.
    #[cfg(feature = "complex")]
    pub fn c64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_double) })
    }

    /// Returns the C `_Complex long double` type.
    ///
    /// This item is enabled by `#[cfg(feature = "complex")]`.
    #[cfg(feature = "complex")]
    #[cfg(not(all(target_arch = "arm")))]
    pub fn complex_longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
    }

    /// Constructs a structure type whose fields have the given types.
    pub fn structure(fields: I) -> Self
    where
        I: IntoIterator<Item = Type>,
        I::IntoIter: ExactSizeIterator<Item = Type>,
    {
        Type(unsafe { Unique::new(ffi_type_struct_create(fields.into_iter())) })
    }

    /// Gets a raw pointer to the underlying
    /// [`ffi_type`](../raw/struct._ffi_type.html).
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../low/index.html) and
    /// [`raw`](../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        *self.0
    }
}

impl TypeArray {
    /// Constructs an array the given `Type`s.
    pub fn new(elements: I) -> Self
    where
        I: IntoIterator<Item = Type>,
        I::IntoIter: ExactSizeIterator<Item = Type>,
    {
        TypeArray(unsafe { Unique::new(ffi_type_array_create(elements.into_iter())) })
    }

    /// Gets a raw pointer to the underlying C array of
    /// [`ffi_type`](../raw/struct._ffi_type.html)s.
    ///
    /// The C array is null-terminated.
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../low/index.html) and
    /// [`raw`](../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        *self.0
    }
}

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

    #[test]
    fn create_u64() {
        Type::u64();
    }

    #[test]
    fn clone_u64() {
        let _ = Type::u64().clone().clone();
    }

    #[test]
    fn create_struct() {
        Type::structure(vec![Type::i64(), Type::i64(), Type::u64()]);
    }

    #[test]
    fn clone_struct() {
        let _ = Type::structure(vec![Type::i64(), Type::i64(), Type::u64()])
            .clone()
            .clone();
    }
}
<commit_msg>Fixed typo<commit_after>//! Representations of C types and arrays thereof.
//!
//! These are used to describe the types of the arguments and results of
//! functions. When we construct a CIF (“Call InterFace”),
//! we provide a sequence of argument types and a result type, and
//! libffi uses this to figure out how to set up a call to a function
//! with those types.

use libc;
use std::fmt;
use std::mem;
use std::ptr;

use crate::low;

use super::util::Unique;

// Internally we represent types and type arrays using raw pointers,
// since this is what libffi understands. Below we wrap them with
// types that implement Drop and Clone.

type Type_ = *mut low::ffi_type;
type TypeArray_ = *mut Type_;

// Informal indication that the object should be considered owned by
// the given reference.
type Owned<T> = T;

/// Represents a single C type.
///
/// # Example
///
/// Suppose we have a C struct:
///
/// ```c
/// struct my_struct {
///     uint16_t f1;
///     uint64_t f2;
/// };
/// ```
///
/// To pass the struct by value via libffi, we need to construct a
/// `Type` object describing its layout:
///
/// ```
/// use libffi::middle::Type;
///
/// let my_struct = Type::structure(vec![
///     Type::u64(),
///     Type::u16(),
/// ]);
/// ```
pub struct Type(Unique<low::ffi_type>);

/// Represents a sequence of C types.
///
/// This can be used to construct a struct type or as the arguments
/// when creating a [`Cif`](struct.Cif.html).
pub struct TypeArray(Unique<*mut low::ffi_type>);

impl fmt::Debug for Type {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("Type({:?})", *self.0))
    }
}

impl fmt::Debug for TypeArray {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("TypeArray({:?})", *self.0))
    }
}

/// Computes the length of a raw `TypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: TypeArray_) -> usize {
    let mut count = 0;
    while !(*array).is_null() {
        count += 1;
        array = array.offset(1);
    }
    count
}

/// Creates an empty `TypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<TypeArray_> {
    let array = libc::malloc((len + 1) * mem::size_of::<Type_>()) as TypeArray_;
    assert!(
        !array.is_null(),
        "ffi_type_array_create_empty: out of memory"
    );
    *array.add(len) = ptr::null_mut::<low::ffi_type>() as Type_;
    array
}

/// Creates a null-terminated array of Type_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: I) -> Owned<TypeArray_>
where
    I: ExactSizeIterator<Item = Type>,
{
    let size = elements.len();
    let new = ffi_type_array_create_empty(size);
    for (i, element) in elements.enumerate() {
        *new.add(i) = *element.0;
        mem::forget(element);
    }

    new
}

/// Creates a struct type from a raw array of element types.
unsafe fn ffi_type_struct_create_raw(elements: Owned<TypeArray_>) -> Owned<Type_> {
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as Type_;
    assert!(!new.is_null(), "ffi_type_struct_create_raw: out of memory");

    (*new).size = 0;
    (*new).alignment = 0;
    (*new).type_ = low::type_tag::STRUCT;
    (*new).elements = elements;

    new
}

/// Creates a struct `ffi_type` with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: I) -> Owned<Type_>
where
    I: ExactSizeIterator<Item = Type>,
{
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

/// Makes a copy of a type array.
unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
    let size = ffi_type_array_len(old);
    let new = ffi_type_array_create_empty(size);

    for i in 0..size {
        *new.add(i) = ffi_type_clone(*old.add(i));
    }

    new
}

/// Makes a copy of a type.
unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
    if (*old).type_ == low::type_tag::STRUCT {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys a `TypeArray_` and all of its elements.
unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys a `Type_` if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
    if (*victim).type_ == low::type_tag::STRUCT {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for Type {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(*self.0) }
    }
}

impl Drop for TypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(*self.0) }
    }
}

impl Clone for Type {
    fn clone(&self) -> Self {
        Type(unsafe { Unique::new(ffi_type_clone(*self.0)) })
    }
}

impl Clone for TypeArray {
    fn clone(&self) -> Self {
        TypeArray(unsafe { Unique::new(ffi_type_array_clone(*self.0)) })
    }
}

macro_rules! match_size_signed {
    ( $name:ident ) => {
        match mem::size_of::<libc::$name>() {
            1 => Self::i8(),
            2 => Self::i16(),
            4 => Self::i32(),
            8 => Self::i64(),
            _ => panic!("Strange size for C type"),
        }
    };
}

macro_rules! match_size_unsigned {
    ( $name:ident ) => {
        match mem::size_of::<libc::$name>() {
            1 => Self::u8(),
            2 => Self::u16(),
            4 => Self::u32(),
            8 => Self::u64(),
            _ => panic!("Strange size for C type"),
        }
    };
}

impl Type {
    /// Returns the representation of the C `void` type.
    ///
    /// This is used only for the return type of a CIF, not for an
    /// argument or struct member.
    pub fn void() -> Self {
        Type(unsafe { Unique::new(&mut low::types::void) })
    }

    /// Returns the unsigned 8-bit numeric type.
    pub fn u8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint8) })
    }

    /// Returns the signed 8-bit numeric type.
    pub fn i8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint8) })
    }

    /// Returns the unsigned 16-bit numeric type.
    pub fn u16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint16) })
    }

    /// Returns the signed 16-bit numeric type.
    pub fn i16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint16) })
    }

    /// Returns the unsigned 32-bit numeric type.
    pub fn u32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint32) })
    }

    /// Returns the signed 32-bit numeric type.
    pub fn i32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint32) })
    }

    /// Returns the unsigned 64-bit numeric type.
    pub fn u64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint64) })
    }

    /// Returns the signed 64-bit numeric type.
    pub fn i64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint64) })
    }

    #[cfg(target_pointer_width = "16")]
    /// Returns the C equivalent of Rust `usize` (`u16`).
    pub fn usize() -> Self {
        Self::u16()
    }

    #[cfg(target_pointer_width = "16")]
    /// Returns the C equivalent of Rust `isize` (`i16`).
    pub fn isize() -> Self {
        Self::i16()
    }

    #[cfg(target_pointer_width = "32")]
    /// Returns the C equivalent of Rust `usize` (`u32`).
    pub fn usize() -> Self {
        Self::u32()
    }

    #[cfg(target_pointer_width = "32")]
    /// Returns the C equivalent of Rust `isize` (`i32`).
    pub fn isize() -> Self {
        Self::i32()
    }

    #[cfg(target_pointer_width = "64")]
    /// Returns the C equivalent of Rust `usize` (`u64`).
    pub fn usize() -> Self {
        Self::u64()
    }

    #[cfg(target_pointer_width = "64")]
    /// Returns the C equivalent of Rust `isize` (`i64`).
    pub fn isize() -> Self {
        Self::i64()
    }

    /// Returns the C `signed char` type.
    pub fn c_schar() -> Self {
        match_size_signed!(c_schar)
    }

    /// Returns the C `unsigned char` type.
    pub fn c_uchar() -> Self {
        match_size_unsigned!(c_uchar)
    }

    /// Returns the C `short` type.
    pub fn c_short() -> Self {
        match_size_signed!(c_short)
    }

    /// Returns the C `unsigned short` type.
    pub fn c_ushort() -> Self {
        match_size_unsigned!(c_ushort)
    }

    /// Returns the C `int` type.
    pub fn c_int() -> Self {
        match_size_signed!(c_int)
    }

    /// Returns the C `unsigned int` type.
    pub fn c_uint() -> Self {
        match_size_unsigned!(c_uint)
    }

    /// Returns the C `long` type.
    pub fn c_long() -> Self {
        match_size_signed!(c_long)
    }

    /// Returns the C `unsigned long` type.
    pub fn c_ulong() -> Self {
        match_size_unsigned!(c_ulong)
    }

    /// Returns the C `longlong` type.
    pub fn c_longlong() -> Self {
        match_size_signed!(c_longlong)
    }

    /// Returns the C `unsigned longlong` type.
    pub fn c_ulonglong() -> Self {
        match_size_unsigned!(c_ulonglong)
    }

    /// Returns the C `float` (32-bit floating point) type.
    pub fn f32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::float) })
    }

    /// Returns the C `double` (64-bit floating point) type.
    pub fn f64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::double) })
    }

    /// Returns the C `void*` type, for passing any kind of pointer.
    pub fn pointer() -> Self {
        Type(unsafe { Unique::new(&mut low::types::pointer) })
    }

    /// Returns the C `long double` (extended-precision floating point) type.
    #[cfg(not(all(target_arch = "arm")))]
    pub fn longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::longdouble) })
    }

    /// Returns the C `_Complex float` type.
    ///
    /// This item is enabled by `#[cfg(feature = "complex")]`.
    #[cfg(feature = "complex")]
    pub fn c32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_float) })
    }

    /// Returns the C `_Complex double` type.
    ///
    /// This item is enabled by `#[cfg(feature = "complex")]`.
    #[cfg(feature = "complex")]
    pub fn c64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_double) })
    }

    /// Returns the C `_Complex long double` type.
    ///
    /// This item is enabled by `#[cfg(feature = "complex")]`.
    #[cfg(feature = "complex")]
    #[cfg(not(all(target_arch = "arm")))]
    pub fn complex_longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
    }

    /// Constructs a structure type whose fields have the given types.
    pub fn structure(fields: I) -> Self
    where
        I: IntoIterator<Item = Type>,
        I::IntoIter: ExactSizeIterator<Item = Type>,
    {
        Type(unsafe { Unique::new(ffi_type_struct_create(fields.into_iter())) })
    }

    /// Gets a raw pointer to the underlying
    /// [`ffi_type`](../raw/struct._ffi_type.html).
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../low/index.html) and
    /// [`raw`](../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        *self.0
    }
}

impl TypeArray {
    /// Constructs an array the given `Type`s.
    pub fn new(elements: I) -> Self
    where
        I: IntoIterator<Item = Type>,
        I::IntoIter: ExactSizeIterator<Item = Type>,
    {
        TypeArray(unsafe { Unique::new(ffi_type_array_create(elements.into_iter())) })
    }

    /// Gets a raw pointer to the underlying C array of
    /// [`ffi_type`](../raw/struct._ffi_type.html)s.
    ///
    /// The C array is null-terminated.
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../low/index.html) and
    /// [`raw`](../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        *self.0
    }
}

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

    #[test]
    fn create_u64() {
        Type::u64();
    }

    #[test]
    fn clone_u64() {
        let _ = Type::u64().clone().clone();
    }

    #[test]
    fn create_struct() {
        Type::structure(vec![Type::i64(), Type::i64(), Type::u64()]);
    }

    #[test]
    fn clone_struct() {
        let _ = Type::structure(vec![Type::i64(), Type::i64(), Type::u64()])
            .clone()
            .clone();
    }
}
<|endoftext|>


<commit_before>#![feature(tcp)]

use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io;
use std::env;
use std::mem;
use std::str::FromStr;
use std::io::Read;
use std::io::Write;

fn main() {
    let port_ : Option<String> = env::args().skip(2).next();
    if let None = port_ {
        println!("usage: {} -p port", env::args().next().unwrap());
        return;
    }

    let port = u16::from_str(&port_.unwrap());
    if let Err(ref e) = port {
        println!("invalid port number given: {}", e);
        return;
    }

    let listener = TcpListener::bind(("127.0.0.1", port.unwrap()));
    if let Err(ref e) = listener {
        println!("failed to listen on port: {}", e);
        return;
    }

    for stream in listener.unwrap().incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream)
                });
            }
            Err(e) => {
                println!("failed to accept connection: {}", e);
            }
        }
    }
}

fn handle_client(mut stream: TcpStream) {
    let mut challenge : u32 = 0;
    let buf : &mut [u8; 4] = unsafe{ mem::transmute(&mut challenge) };
    let mut nread;

    let _ = stream.set_nodelay(true);

    loop {
        nread = 0;
        while nread < buf.len() {
            match stream.read(&mut buf[nread..]) {
                Ok(n) if n == 0 => return,
                Ok(n) => nread += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
                Err(e) => {
                    println!("{}", e);
                    return;
                }
            }
        }

        challenge = u32::from_be(challenge);
        if challenge == 0 {
            std::process::exit(0);
        }
        challenge = u32::to_be(challenge + 1);

        let mut nwritten = 0;
        while nwritten < buf.len() {
            match stream.write(&buf[nwritten..]) {
                Ok(n) => nwritten += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
                Err(e) => {
                    println!("{}", e);
                    return;
                }
            }
        }
    }
}
<commit_msg>Avoid undefined behavior; don't alias mutable ptrs<commit_after>#![feature(tcp)]

use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io;
use std::env;
use std::mem;
use std::str::FromStr;
use std::io::Read;
use std::io::Write;

fn main() {
    let port_ : Option<String> = env::args().skip(2).next();
    if let None = port_ {
        println!("usage: {} -p port", env::args().next().unwrap());
        return;
    }

    let port = u16::from_str(&port_.unwrap());
    if let Err(ref e) = port {
        println!("invalid port number given: {}", e);
        return;
    }

    let listener = TcpListener::bind(("127.0.0.1", port.unwrap()));
    if let Err(ref e) = listener {
        println!("failed to listen on port: {}", e);
        return;
    }

    for stream in listener.unwrap().incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream)
                });
            }
            Err(e) => {
                println!("failed to accept connection: {}", e);
            }
        }
    }
}

fn handle_client(mut stream: TcpStream) {
    let mut buf = [0u8; 4];
    let mut challenge = 0u32;
    let mut nread;

    let _ = stream.set_nodelay(true);

    loop {
        nread = 0;
        while nread < buf.len() {
            match stream.read(&mut buf[nread..]) {
                Ok(n) if n == 0 => return,
                Ok(n) => nread += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
                Err(e) => {
                    println!("{}", e);
                    return;
                }
            }
        }

        challenge = unsafe { mem::transmute(buf) };
        challenge = u32::from_be(challenge);
        if challenge == 0 {
            std::process::exit(0);
        }
        challenge = u32::to_be(challenge + 1);
        buf = unsafe { mem::transmute(challenge) };

        let mut nwritten = 0;
        while nwritten < buf.len() {
            match stream.write(&buf[nwritten..]) {
                Ok(n) => nwritten += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
                Err(e) => {
                    println!("{}", e);
                    return;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate cmake;
extern crate gcc;
extern crate pkg_config;

use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e{
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn main() {
    let https = env::var("CARGO_FEATURE_HTTPS").is_ok();
    let ssh = env::var("CARGO_FEATURE_SSH").is_ok();
    let curl = env::var("CARGO_FEATURE_CURL").is_ok();
    if ssh {
        register_dep("SSH2");
    }
    if https {
        register_dep("OPENSSL");
    }
    if curl {
        register_dep("CURL");
    }
    let has_pkgconfig = Command::new("pkg-config").output().is_ok();

    if env::var("LIBGIT2_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libgit2").is_ok() {
            return
        }
    }

    if !Path::new("libgit2/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let windows = target.contains("windows");
    let msvc = target.contains("msvc");
    let mut cfg = cmake::Config::new("libgit2");

    if msvc {
        // libgit2 passes the /GL flag to enable whole program optimization, but
        // this requires that the /LTCG flag is passed to the linker later on,
        // and currently the compiler does not do that, so we disable whole
        // program optimization entirely.
        cfg.cflag("/GL-");

        // Currently liblibc links to msvcrt which apparently is a dynamic CRT,
        // so we need to turn this off to get it to link right.
        let features = env::var("CARGO_CFG_TARGET_FEATURE")
                          .unwrap_or(String::new());
        if features.contains("crt-static") {
            cfg.define("STATIC_CRT", "ON");
        } else {
            cfg.define("STATIC_CRT", "OFF");
        }
    }

    // libgit2 uses pkg-config to discover libssh2, but this doesn't work on
    // windows as libssh2 doesn't come with a libssh2.pc file in that install
    // (or when pkg-config isn't found). As a result we just manually turn on
    // SSH support in libgit2 (a little jankily) here...
    if ssh && (windows || !has_pkgconfig) {
        if let Ok(libssh2_include) = env::var("DEP_SSH2_INCLUDE") {
            if msvc {
                cfg.cflag(format!("/I{}", libssh2_include))
                   .cflag("/DGIT_SSH");
            } else {
                cfg.cflag(format!("-I{}", libssh2_include))
                   .cflag("-DGIT_SSH");
            }
        }
    }

    // When cross-compiling, we're pretty unlikely to find a `dlltool` binary
    // lying around, so try to find another if it exists
    if windows && !host.contains("windows") {
        let c_compiler = gcc::Config::new().cargo_metadata(false)
                                           .get_compiler();
        let exe = c_compiler.path();
        let path = env::var_os("PATH").unwrap_or(OsString::new());
        let exe = env::split_paths(&path)
                      .map(|p| p.join(&exe))
                      .find(|p| p.exists());
        if let Some(exe) = exe {
            if let Some(name) = exe.file_name().and_then(|e| e.to_str()) {
                let name = name.replace("gcc", "dlltool");
                let dlltool = exe.with_file_name(name);
                cfg.define("DLLTOOL", &dlltool);
            }
        }
    }

    if ssh {
        cfg.register_dep("SSH2");
    } else {
        cfg.define("USE_SSH", "OFF");
    }
    if https {
        cfg.register_dep("OPENSSL");
    } else {
        cfg.define("USE_OPENSSL", "OFF");
    }
    if curl {
        cfg.register_dep("CURL");
    } else {
        cfg.define("CURL", "OFF");
    }

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
                 .define("BUILD_CLAR", "OFF")
                 .register_dep("Z")
                 .build();

    // Make sure libssh2 was detected on unix systems, because it definitely
    // should have been!
    if ssh && !msvc {
        let flags = dst.join("build/CMakeFiles/git2.dir/flags.make");
        let mut contents = String::new();
        t!(t!(File::open(flags)).read_to_string(&mut contents));
        if !contents.contains("-DGIT_SSH") {
            panic!("libgit2 failed to find libssh2, and SSH support is required");
        }
    }

    // libgit2 requires the http_parser library for the HTTP transport to be
    // implemented, and it will attempt to use the system http_parser if it's
    // available. Detect this situation and report using the system http parser
    // the same way in this situation.
    //
    // Note that other dependencies of libgit2 like openssl, libz, and libssh2
    // are tracked via crates instead of this. Ideally this should be a crate as
    // well.
    let pkgconfig_file = dst.join("lib/pkgconfig/libgit2.pc");
    if let Ok(mut f) = File::open(&pkgconfig_file) {
        let mut contents = String::new();
        t!(f.read_to_string(&mut contents));
        if contents.contains("-lhttp_parser") {
            println!("cargo:rustc-link-lib=http_parser");
        }
    }

    if target.contains("windows") {
        println!("cargo:rustc-link-lib=winhttp");
        println!("cargo:rustc-link-lib=rpcrt4");
        println!("cargo:rustc-link-lib=ole32");
        println!("cargo:rustc-link-lib=crypt32");
        println!("cargo:rustc-link-lib=static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    println!("cargo:rustc-link-lib=static=git2");
    println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-link-lib=iconv");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=CoreFoundation");
    }
}

fn register_dep(dep: &str) {
    if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
        prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        return
    }
    if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
        let root = Path::new(&s).parent().unwrap();
        env::set_var(&format!("DEP_{}_ROOT", dep), root);
        let path = root.join("lib/pkgconfig");
        if path.exists() {
            prepend("PKG_CONFIG_PATH", path);
            return
        }
    }
}

fn prepend(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let mut v = vec![val];
    v.extend(env::split_paths(&prefix));
    env::set_var(var, &env::join_paths(v).unwrap());
}
<commit_msg>libgit2-sys: unset DESTDIR during libgit2 build<commit_after>extern crate cmake;
extern crate gcc;
extern crate pkg_config;

use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e{
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn main() {
    let https = env::var("CARGO_FEATURE_HTTPS").is_ok();
    let ssh = env::var("CARGO_FEATURE_SSH").is_ok();
    let curl = env::var("CARGO_FEATURE_CURL").is_ok();
    if ssh {
        register_dep("SSH2");
    }
    if https {
        register_dep("OPENSSL");
    }
    if curl {
        register_dep("CURL");
    }
    let has_pkgconfig = Command::new("pkg-config").output().is_ok();

    if env::var("LIBGIT2_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libgit2").is_ok() {
            return
        }
    }

    if !Path::new("libgit2/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let windows = target.contains("windows");
    let msvc = target.contains("msvc");
    let mut cfg = cmake::Config::new("libgit2");

    if msvc {
        // libgit2 passes the /GL flag to enable whole program optimization, but
        // this requires that the /LTCG flag is passed to the linker later on,
        // and currently the compiler does not do that, so we disable whole
        // program optimization entirely.
        cfg.cflag("/GL-");

        // Currently liblibc links to msvcrt which apparently is a dynamic CRT,
        // so we need to turn this off to get it to link right.
        let features = env::var("CARGO_CFG_TARGET_FEATURE")
                          .unwrap_or(String::new());
        if features.contains("crt-static") {
            cfg.define("STATIC_CRT", "ON");
        } else {
            cfg.define("STATIC_CRT", "OFF");
        }
    }

    // libgit2 uses pkg-config to discover libssh2, but this doesn't work on
    // windows as libssh2 doesn't come with a libssh2.pc file in that install
    // (or when pkg-config isn't found). As a result we just manually turn on
    // SSH support in libgit2 (a little jankily) here...
    if ssh && (windows || !has_pkgconfig) {
        if let Ok(libssh2_include) = env::var("DEP_SSH2_INCLUDE") {
            if msvc {
                cfg.cflag(format!("/I{}", libssh2_include))
                   .cflag("/DGIT_SSH");
            } else {
                cfg.cflag(format!("-I{}", libssh2_include))
                   .cflag("-DGIT_SSH");
            }
        }
    }

    // When cross-compiling, we're pretty unlikely to find a `dlltool` binary
    // lying around, so try to find another if it exists
    if windows && !host.contains("windows") {
        let c_compiler = gcc::Config::new().cargo_metadata(false)
                                           .get_compiler();
        let exe = c_compiler.path();
        let path = env::var_os("PATH").unwrap_or(OsString::new());
        let exe = env::split_paths(&path)
                      .map(|p| p.join(&exe))
                      .find(|p| p.exists());
        if let Some(exe) = exe {
            if let Some(name) = exe.file_name().and_then(|e| e.to_str()) {
                let name = name.replace("gcc", "dlltool");
                let dlltool = exe.with_file_name(name);
                cfg.define("DLLTOOL", &dlltool);
            }
        }
    }

    if ssh {
        cfg.register_dep("SSH2");
    } else {
        cfg.define("USE_SSH", "OFF");
    }
    if https {
        cfg.register_dep("OPENSSL");
    } else {
        cfg.define("USE_OPENSSL", "OFF");
    }
    if curl {
        cfg.register_dep("CURL");
    } else {
        cfg.define("CURL", "OFF");
    }

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    // Unset DESTDIR or libgit2.a ends up in it and cargo can't find it
    env::remove_var("DESTDIR");
    let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
                 .define("BUILD_CLAR", "OFF")
                 .register_dep("Z")
                 .build();

    // Make sure libssh2 was detected on unix systems, because it definitely
    // should have been!
    if ssh && !msvc {
        let flags = dst.join("build/CMakeFiles/git2.dir/flags.make");
        let mut contents = String::new();
        t!(t!(File::open(flags)).read_to_string(&mut contents));
        if !contents.contains("-DGIT_SSH") {
            panic!("libgit2 failed to find libssh2, and SSH support is required");
        }
    }

    // libgit2 requires the http_parser library for the HTTP transport to be
    // implemented, and it will attempt to use the system http_parser if it's
    // available. Detect this situation and report using the system http parser
    // the same way in this situation.
    //
    // Note that other dependencies of libgit2 like openssl, libz, and libssh2
    // are tracked via crates instead of this. Ideally this should be a crate as
    // well.
    let pkgconfig_file = dst.join("lib/pkgconfig/libgit2.pc");
    if let Ok(mut f) = File::open(&pkgconfig_file) {
        let mut contents = String::new();
        t!(f.read_to_string(&mut contents));
        if contents.contains("-lhttp_parser") {
            println!("cargo:rustc-link-lib=http_parser");
        }
    }

    if target.contains("windows") {
        println!("cargo:rustc-link-lib=winhttp");
        println!("cargo:rustc-link-lib=rpcrt4");
        println!("cargo:rustc-link-lib=ole32");
        println!("cargo:rustc-link-lib=crypt32");
        println!("cargo:rustc-link-lib=static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    println!("cargo:rustc-link-lib=static=git2");
    println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-link-lib=iconv");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=CoreFoundation");
    }
}

fn register_dep(dep: &str) {
    if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
        prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        return
    }
    if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
        let root = Path::new(&s).parent().unwrap();
        env::set_var(&format!("DEP_{}_ROOT", dep), root);
        let path = root.join("lib/pkgconfig");
        if path.exists() {
            prepend("PKG_CONFIG_PATH", path);
            return
        }
    }
}

fn prepend(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let mut v = vec![val];
    v.extend(env::split_paths(&prefix));
    env::set_var(var, &env::join_paths(v).unwrap());
}
<|endoftext|>


<commit_before>extern crate phf;

use glib::translate::*;
use glib_sys;
use libc;
use std::str::FromStr;

use util::utf8_cstr;

include!(concat!(env!("OUT_DIR"), "/attributes-codegen.rs"));

impl FromStr for Attribute {
    type Err = ();

    fn from_str(s: &str) -> Result<Attribute, ()> {
        ATTRIBUTES.get(s).cloned().ok_or(())
    }
}

#[no_mangle]
pub extern "C" fn rsvg_attribute_from_name(
    raw_name: *const libc::c_char,
    out_attr: *mut Attribute,
) -> glib_sys::gboolean {
    let name = unsafe { utf8_cstr(raw_name) };

    match Attribute::from_str(name) {
        Ok(a) => {
            unsafe {
                *out_attr = a;
            }
            true.to_glib()
        }

        Err(_) => false.to_glib(),
    }
}

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

    #[test]
    fn parses_attributes() {
        assert_eq!(Attribute::from_str("width"), Ok(Attribute::Width));
    }

    #[test]
    fn unknown_attribute_yields_error() {
        assert_eq!(Attribute::from_str("foobar"), Err(()));
    }

    #[test]
    fn c_attribute_from_name() {
        let mut a: Attribute = unsafe { mem::uninitialized() };
        let res: bool = from_glib(rsvg_attribute_from_name(
            "width".to_glib_none().0,
            &mut a as *mut Attribute,
        ));
        assert!(res);
        assert_eq!(a, Attribute::Width);
    }

    #[test]
    fn invalid_c_attribute_from_name() {
        let mut a: Attribute = unsafe { mem::uninitialized() };
        let res: bool = from_glib(rsvg_attribute_from_name(
            "foobar".to_glib_none().0,
            &mut a as *mut Attribute,
        ));
        assert!(!res);
    }
}
<commit_msg>Attribute::to_str() - New function, hopefully only used for printing errors<commit_after>extern crate phf;

use glib::translate::*;
use glib_sys;
use libc;
use std::str::FromStr;

use util::utf8_cstr;

include!(concat!(env!("OUT_DIR"), "/attributes-codegen.rs"));

impl FromStr for Attribute {
    type Err = ();

    fn from_str(s: &str) -> Result<Attribute, ()> {
        ATTRIBUTES.get(s).cloned().ok_or(())
    }
}

impl Attribute {
    // This is horribly inefficient, but for now I'm too lazy to have a
    // compile-time bijective mapping from attributes to names.  Hopefully
    // this function is only called when *printing* errors, which, uh,
    // should not be done too often.
    pub fn to_str(&self) -> &'static str {
        for (k, v) in ATTRIBUTES.entries() {
            if *v == *self {
                return k;
            }
        }

        unreachable!();
    }
}

#[no_mangle]
pub extern "C" fn rsvg_attribute_from_name(
    raw_name: *const libc::c_char,
    out_attr: *mut Attribute,
) -> glib_sys::gboolean {
    let name = unsafe { utf8_cstr(raw_name) };

    match Attribute::from_str(name) {
        Ok(a) => {
            unsafe {
                *out_attr = a;
            }
            true.to_glib()
        }

        Err(_) => false.to_glib(),
    }
}

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

    #[test]
    fn parses_attributes() {
        assert_eq!(Attribute::from_str("width"), Ok(Attribute::Width));
    }

    #[test]
    fn unknown_attribute_yields_error() {
        assert_eq!(Attribute::from_str("foobar"), Err(()));
    }

    #[test]
    fn c_attribute_from_name() {
        let mut a: Attribute = unsafe { mem::uninitialized() };
        let res: bool = from_glib(rsvg_attribute_from_name(
            "width".to_glib_none().0,
            &mut a as *mut Attribute,
        ));
        assert!(res);
        assert_eq!(a, Attribute::Width);
    }

    #[test]
    fn invalid_c_attribute_from_name() {
        let mut a: Attribute = unsafe { mem::uninitialized() };
        let res: bool = from_glib(rsvg_attribute_from_name(
            "foobar".to_glib_none().0,
            &mut a as *mut Attribute,
        ));
        assert!(!res);
    }

    #[test]
    fn converts_attributes_back_to_strings() {
        assert_eq!(Attribute::ClipPath.to_str(), "clip-path");
        assert_eq!(Attribute::KernelUnitLength.to_str(), "kernelUnitLength");
        assert_eq!(Attribute::Offset.to_str(), "offset");
    }
}
<|endoftext|>