<commit_before>use helpers::*;
use core::cell::Cell;
use core::cmp;

use hil;
use hil::spi_master;
use hil::spi_master::SpiCallback;
use hil::spi_master::ClockPolarity;
use hil::spi_master::ClockPhase;
use dma::DMAChannel;
use dma::DMAClient;
use gpio::PC;

/// Implementation of DMA-based SPI master communication for
/// the Atmel SAM4L CortexM4 microcontroller.
/// Authors: Sam Crow <samcrow@uw.edu>
///          Philip Levis <pal@cs.stanfored.edu>
///
// Driver for the SPI hardware (seperate from the USARTS),
// described in chapter 26 of the datasheet

/// The registers used to interface with the hardware
#[repr(C, packed)]
struct SpiRegisters {
    cr: u32, // 0x0
    mr: u32, // 0x4
    rdr: u32, // 0x8
    tdr: u32, // 0xC
    sr: u32, // 0x10
    ier: u32, // 0x14
    idr: u32, // 0x18
    imr: u32, // 0x1C
    reserved0: [u32; 4], // 0x20, 0x24, 0x28, 0x2C
    csr0: u32, // 0x30
    csr1: u32, // 0x34
    csr2: u32, // 0x38
    csr3: u32, // 0x3C
    reserved1: [u32; 41], // 0x40 - 0xE0
    wpcr: u32, // 0xE4
    wpsr: u32, // 0xE8
    reserved2: [u32; 3], // 0xEC - 0xF4
    features: u32, // 0xF8
    version: u32, // 0xFC
}

const SPI_BASE: u32 = 0x40008000;

/// Values for selected peripherals
#[derive(Copy,Clone)]
pub enum Peripheral {
    Peripheral0,
    Peripheral1,
    Peripheral2,
    Peripheral3,
}

///
/// The SAM4L supports four peripherals.
pub struct Spi {
    regs: *mut SpiRegisters,
    callback: Option<&'static SpiCallback>,
    dma_read:  Option<&'static mut DMAChannel>,
    dma_write: Option<&'static mut DMAChannel>,
    // keep track of which // interrupts are pending in order
    // to correctly issue completion event only after both complete.
    reading: Cell<bool>,
    writing: Cell<bool>,
}

pub static mut SPI: Spi = Spi::new();

impl Spi {
   /// Creates a new SPI object, with peripheral 0 selected
   pub const fn new() -> Spi {
        Spi {
            regs: SPI_BASE as *mut SpiRegisters,
            callback: None,
            dma_read:  None,
            dma_write: None,
            reading: Cell::new(false),
            writing: Cell::new(false)
        }
    }

    pub fn enable(&self) {
        self.dma_read.as_ref().map(|read| read.enable());
        self.dma_write.as_ref().map(|write| write.enable());
        unsafe { volatile_store(&mut (*self.regs).cr, 0b1); }
    }

    pub fn disable(&self) {
        self.dma_read.as_ref().map(|read| read.disable());
        self.dma_write.as_ref().map(|write| write.disable());
        unsafe { volatile_store(&mut (*self.regs).cr, 0b10); }
    }

    /// Sets the approximate baud rate for the active peripheral,
    /// and return the actual baud rate set.
    ///
    /// Since the only supported baud rates are 48 MHz / n where n
    /// is an integer from 1 to 255, the exact baud rate may not
    /// be available. In that case, the next lower baud rate will
    /// be selected.
    ///
    /// The lowest available baud rate is 188235 baud. If the
    /// requested rate is lower, 188235 baud will be selected.
    pub fn set_baud_rate(&self, rate: u32) -> u32 {
        // Main clock frequency
        let mut real_rate = rate;
        let clock = 48000000;

        if real_rate < 188235 {
            real_rate = 188235;
        }
        if real_rate > clock {
            real_rate = clock;
        }

        // Divide and truncate, resulting in a n value that might be too low
        let mut scbr = clock / real_rate;
        // If the division was not exact, increase the n to get a slower baud rate
        if clock % rate != 0 {
            scbr += 1;
        }
        let mut csr = self.read_active_csr();
        let csr_mask: u32 = 0xFFFF00FF;
        // Clear, then write CSR bits
        csr &= csr_mask;
        csr |= (scbr & 0xFF) << 8;
        self.write_active_csr(csr);
        clock / scbr
    }

    pub fn set_active_peripheral(&self, peripheral: Peripheral) {
        let peripheral_number: u32 = match peripheral {
            Peripheral::Peripheral0 => 0b0000,
            Peripheral::Peripheral1 => 0b0001,
            Peripheral::Peripheral2 => 0b0011,
            Peripheral::Peripheral3 => 0b0111
        };
        let mut mr = unsafe { volatile_load(& (*self.regs).mr) };
        let pcs_mask: u32 = 0xFFF0FFFF;
        mr &= pcs_mask;
        mr |= peripheral_number << 16;
        unsafe { volatile_store(&mut (*self.regs).mr, mr); }
    }

    /// Returns the currently active peripheral
    pub fn get_active_peripheral(&self) -> Peripheral {
        let mr = unsafe {volatile_load(&(*self.regs).mr)};
        let pcs = (mr >> 16) & 0xF;
        // Split into bits for matching
        let pcs_bits = ((pcs >> 3) & 1, (pcs >> 2) & 1, (pcs >> 1) & 1, pcs & 1);
        match pcs_bits {
            (_, _, _, 0) => Peripheral::Peripheral0,
            (_, _, 0, 1) => Peripheral::Peripheral1,
            (_, 0, 1, 1) => Peripheral::Peripheral2,
            (0, 1, 1, 1) => Peripheral::Peripheral3,
            _ => {
                // Invalid configuration
                // ???
                Peripheral::Peripheral0
            }
        }
    }

    /// Returns the value of CSR0, CSR1, CSR2, or CSR3,
    /// whichever corresponds to the active peripheral
    fn read_active_csr(&self) -> u32 {
        match self.get_active_peripheral() {
            Peripheral::Peripheral0 => unsafe {volatile_load(&(*self.regs).csr0)},
            Peripheral::Peripheral1 => unsafe {volatile_load(&(*self.regs).csr1)},
            Peripheral::Peripheral2 => unsafe {volatile_load(&(*self.regs).csr2)},
            Peripheral::Peripheral3 => unsafe {volatile_load(&(*self.regs).csr3)},
        }
    }
    /// Sets the Chip Select Register (CSR) of the active peripheral
    /// (CSR0, CSR1, CSR2, or CSR3).
    fn write_active_csr(&self, value: u32) {
        match self.get_active_peripheral() {
            Peripheral::Peripheral0 => unsafe {volatile_store(&mut (*self.regs).csr0, value)},
            Peripheral::Peripheral1 => unsafe {volatile_store(&mut (*self.regs).csr1, value)},
            Peripheral::Peripheral2 => unsafe {volatile_store(&mut (*self.regs).csr2, value)},
            Peripheral::Peripheral3 => unsafe {volatile_store(&mut (*self.regs).csr3, value)},
        };
    }

    /// Set the DMA channels used for reading and writing.
    pub fn set_dma(&mut self, read: &'static mut DMAChannel, write: &'static mut DMAChannel) {
        self.dma_read = Some(read);
        self.dma_write = Some(write);
    }
}

impl spi_master::SpiMaster for Spi {
    /// By default, initialize SPI to operate at 40KHz, clock is
    /// idle on low, and sample on the leading edge.
    fn init(&mut self, callback: &'static SpiCallback) {
        self.callback = Some(callback);
        self.set_rate(40000); // Set initial baud rate to 8MHz
        self.set_clock(ClockPolarity::IdleLow);
        self.set_phase(ClockPhase::SampleLeading);

        // Keep slave select active until a last transfer bit is set
        let mut csr = self.read_active_csr();
        csr |= 1 << 3;
        self.write_active_csr(csr);

        // Indicate the last transfer to disable slave select
        unsafe {volatile_store(&mut (*self.regs).cr, 1 << 24)};

        let mut mode = unsafe {volatile_load(&(*self.regs).mr)};
        mode |= 1; // Enable master mode
        mode |= 1 << 4; // Disable mode fault detection (open drain outputs not supported)
        unsafe {volatile_store(&mut (*self.regs).mr, mode)};

    }

    fn is_busy(&self) -> bool {
        self.reading.get() || self.writing.get()
    }

    /// Write a byte to the SPI and return the read; if an
    /// asynchronous operation is outstanding, do nothing.
    fn read_write_byte(&self, val: u8) -> u8 {
        if self.reading.get() || self.writing.get() {
  //          return 0;
        }
        self.write_byte(val);
        // Wait for receive data register full
        while (unsafe {volatile_load(&(*self.regs).sr)} & 1) != 1 {}
        // Return read value
        unsafe {volatile_load(&(*self.regs).rdr) as u8}
    }

    /// Write a byte to the SPI and discard the read; if an
    /// asynchronous operation is outstanding, do nothing.
    fn write_byte(&self, out_byte: u8) {
        if self.reading.get() || self.writing.get() {
 //           return;
        }
        let tdr = out_byte as u32;
        // Wait for data to leave TDR and enter serializer, so TDR is free
        // for this next byte
        while (unsafe {volatile_load(& (*self.regs).sr)} & 1 << 1) == 0 {}
        unsafe {volatile_store(&mut (*self.regs).tdr, tdr)};
    }

    /// Write 0 to the SPI and return the read; if an
    /// asynchronous operation is outstanding, do nothing.
    fn read_byte(&self) -> u8 {
        self.read_write_byte(0)
    }

    /// Asynchonous buffer read/write of SPI.
    /// write_buffer must  be Some; read_buffer may be None;
    /// if read_buffer is Some, then length of read/write is the
    /// minimum of two buffer lengths; returns true if operation
    /// starts (will receive callback through SpiClient), returns
    /// false if the operation does not start.
    // The write buffer has to be mutable because it's passed back to
    // the caller, and the caller may want to be able write into it.
    //
    // A better version of this would
    fn read_write_bytes(&self,
                        write_buffer:  Option<&'static mut [u8]>,
                        read_buffer: Option<&'static mut [u8]>,
                        len: usize) -> bool {
        let writing = write_buffer.is_some();
        let reading = read_buffer.is_some();
        // If there is no write buffer, or busy, then don't start.
        // Need to check self.reading as well as self.writing in case
        // write interrupt comes back first.
        if !writing  || self.reading.get() || self.writing.get() {
//            return false
        }

        let pc18 = unsafe {&PC[18] as &hil::gpio::GPIOPin};
        pc18.toggle();
        // Need to mark if reading or writing so we correctly
        // regenerate Options on callback
        self.writing.set(writing);
        self.reading.set(reading);

        let read_len = match read_buffer {
            Some(ref buf) => {buf.len()},
            None          => 0
        };
        let write_len = match write_buffer {
            Some(ref buf) => {buf.len()},
            None          => 0
        };
        let buflen = if !reading {write_len}
                     else        {cmp::min(read_len, write_len)};
        let count = cmp::min(buflen, len);

        // The ordering of these operations matters; if you enable then
        // perform the operation, you can read a byte early on the SPI data register
        if reading {
            self.dma_read.as_ref().map(|read| read.do_xfer_buf(4, read_buffer, count));
        }
        self.dma_write.as_ref().map(|write| write.do_xfer_buf(22, write_buffer, count));
        if reading {
            self.dma_read.as_ref().map(|read| read.enable());
        }
        self.dma_write.as_ref().map(|write| write.enable());
        true
    }

    fn set_rate(&self, rate: u32) -> u32 {
        self.set_baud_rate(rate)
     }

    fn set_clock(&self, polarity: ClockPolarity) {
        let mut csr = self.read_active_csr();
        match polarity {
            ClockPolarity::IdleHigh => csr |= 1,
            ClockPolarity::IdleLow => csr &= 0xFFFFFFFE,
        };
        self.write_active_csr(csr);
    }

    fn set_phase(&self, phase: ClockPhase) {
        let mut csr = self.read_active_csr();
        match phase {
            ClockPhase::SampleLeading => csr |= 1 << 1,
            ClockPhase::SampleTrailing => csr &= 0xFFFFFFFD,
        };
        self.write_active_csr(csr);
    }

    fn set_chip_select(&self, cs: u8) -> bool{
        if cs >= 4 {
            return false
        }
        let peripheral_number: u32 = match cs {
            0 => 0b0000,
            1 => 0b0001,
            2 => 0b0011,
            3 => 0b0111,
            _ => 0b0000,
        };

        let mut mr = unsafe {volatile_load(&(*self.regs).mr)};
        // Clear and set MR.PCS
        let pcs_mask: u32 = 0xFFF0FFFF;
        mr &= pcs_mask;
        mr |= peripheral_number << 16;
        unsafe {volatile_store(&mut (*self.regs).mr, mr);}
        true
    }

    fn clear_chip_select(&self) {
       unsafe {volatile_store(&mut (*self.regs).cr, 1 << 24)};
    }
}

impl DMAClient for Spi {
    fn xfer_done(&mut self, pid: usize) {
        // I don't know if there are ordering guarantees on the read and
        // write interrupts, guessing not, so issue the callback when both
        // reading and writing are complete. In practice it seems like
        // the read interrupt happens second. -pal
        //
        // The disable calls are commented out because executing them
        // causes subsequent operations to fail. The call to read_write_bytes
        // calls enable(), so I don't know why. -pal
        if pid == 4  { // SPI RX
           // self.dma_read.as_ref().map(|dma| dma.disable());
            self.reading.set(false);
            if !self.reading.get() && !self.writing.get() {
                self.callback.as_ref().map(|cb| cb.read_write_done());
            }
        }
        if pid == 22 { // SPI TX
           // self.dma_write.as_ref().map(|dma| dma.disable());
            self.writing.set(false);
            if !self.reading.get() && !self.writing.get() {
                self.callback.as_ref().map(|cb| cb.read_write_done());
            }
        }
    }
}
<commit_msg>Remove incorrect commenting out of re-entrance guard.<commit_after>use helpers::*;
use core::cell::Cell;
use core::cmp;

use hil;
use hil::spi_master;
use hil::spi_master::SpiCallback;
use hil::spi_master::ClockPolarity;
use hil::spi_master::ClockPhase;
use dma::DMAChannel;
use dma::DMAClient;
use gpio::PC;

/// Implementation of DMA-based SPI master communication for
/// the Atmel SAM4L CortexM4 microcontroller.
/// Authors: Sam Crow <samcrow@uw.edu>
///          Philip Levis <pal@cs.stanfored.edu>
///
// Driver for the SPI hardware (seperate from the USARTS),
// described in chapter 26 of the datasheet

/// The registers used to interface with the hardware
#[repr(C, packed)]
struct SpiRegisters {
    cr: u32, // 0x0
    mr: u32, // 0x4
    rdr: u32, // 0x8
    tdr: u32, // 0xC
    sr: u32, // 0x10
    ier: u32, // 0x14
    idr: u32, // 0x18
    imr: u32, // 0x1C
    reserved0: [u32; 4], // 0x20, 0x24, 0x28, 0x2C
    csr0: u32, // 0x30
    csr1: u32, // 0x34
    csr2: u32, // 0x38
    csr3: u32, // 0x3C
    reserved1: [u32; 41], // 0x40 - 0xE0
    wpcr: u32, // 0xE4
    wpsr: u32, // 0xE8
    reserved2: [u32; 3], // 0xEC - 0xF4
    features: u32, // 0xF8
    version: u32, // 0xFC
}

const SPI_BASE: u32 = 0x40008000;

/// Values for selected peripherals
#[derive(Copy,Clone)]
pub enum Peripheral {
    Peripheral0,
    Peripheral1,
    Peripheral2,
    Peripheral3,
}

///
/// The SAM4L supports four peripherals.
pub struct Spi {
    regs: *mut SpiRegisters,
    callback: Option<&'static SpiCallback>,
    dma_read:  Option<&'static mut DMAChannel>,
    dma_write: Option<&'static mut DMAChannel>,
    // keep track of which // interrupts are pending in order
    // to correctly issue completion event only after both complete.
    reading: Cell<bool>,
    writing: Cell<bool>,
}

pub static mut SPI: Spi = Spi::new();

impl Spi {
   /// Creates a new SPI object, with peripheral 0 selected
   pub const fn new() -> Spi {
        Spi {
            regs: SPI_BASE as *mut SpiRegisters,
            callback: None,
            dma_read:  None,
            dma_write: None,
            reading: Cell::new(false),
            writing: Cell::new(false)
        }
    }

    pub fn enable(&self) {
        self.dma_read.as_ref().map(|read| read.enable());
        self.dma_write.as_ref().map(|write| write.enable());
        unsafe { volatile_store(&mut (*self.regs).cr, 0b1); }
    }

    pub fn disable(&self) {
        self.dma_read.as_ref().map(|read| read.disable());
        self.dma_write.as_ref().map(|write| write.disable());
        unsafe { volatile_store(&mut (*self.regs).cr, 0b10); }
    }

    /// Sets the approximate baud rate for the active peripheral,
    /// and return the actual baud rate set.
    ///
    /// Since the only supported baud rates are 48 MHz / n where n
    /// is an integer from 1 to 255, the exact baud rate may not
    /// be available. In that case, the next lower baud rate will
    /// be selected.
    ///
    /// The lowest available baud rate is 188235 baud. If the
    /// requested rate is lower, 188235 baud will be selected.
    pub fn set_baud_rate(&self, rate: u32) -> u32 {
        // Main clock frequency
        let mut real_rate = rate;
        let clock = 48000000;

        if real_rate < 188235 {
            real_rate = 188235;
        }
        if real_rate > clock {
            real_rate = clock;
        }

        // Divide and truncate, resulting in a n value that might be too low
        let mut scbr = clock / real_rate;
        // If the division was not exact, increase the n to get a slower baud rate
        if clock % rate != 0 {
            scbr += 1;
        }
        let mut csr = self.read_active_csr();
        let csr_mask: u32 = 0xFFFF00FF;
        // Clear, then write CSR bits
        csr &= csr_mask;
        csr |= (scbr & 0xFF) << 8;
        self.write_active_csr(csr);
        clock / scbr
    }

    pub fn set_active_peripheral(&self, peripheral: Peripheral) {
        let peripheral_number: u32 = match peripheral {
            Peripheral::Peripheral0 => 0b0000,
            Peripheral::Peripheral1 => 0b0001,
            Peripheral::Peripheral2 => 0b0011,
            Peripheral::Peripheral3 => 0b0111
        };
        let mut mr = unsafe { volatile_load(& (*self.regs).mr) };
        let pcs_mask: u32 = 0xFFF0FFFF;
        mr &= pcs_mask;
        mr |= peripheral_number << 16;
        unsafe { volatile_store(&mut (*self.regs).mr, mr); }
    }

    /// Returns the currently active peripheral
    pub fn get_active_peripheral(&self) -> Peripheral {
        let mr = unsafe {volatile_load(&(*self.regs).mr)};
        let pcs = (mr >> 16) & 0xF;
        // Split into bits for matching
        let pcs_bits = ((pcs >> 3) & 1, (pcs >> 2) & 1, (pcs >> 1) & 1, pcs & 1);
        match pcs_bits {
            (_, _, _, 0) => Peripheral::Peripheral0,
            (_, _, 0, 1) => Peripheral::Peripheral1,
            (_, 0, 1, 1) => Peripheral::Peripheral2,
            (0, 1, 1, 1) => Peripheral::Peripheral3,
            _ => {
                // Invalid configuration
                // ???
                Peripheral::Peripheral0
            }
        }
    }

    /// Returns the value of CSR0, CSR1, CSR2, or CSR3,
    /// whichever corresponds to the active peripheral
    fn read_active_csr(&self) -> u32 {
        match self.get_active_peripheral() {
            Peripheral::Peripheral0 => unsafe {volatile_load(&(*self.regs).csr0)},
            Peripheral::Peripheral1 => unsafe {volatile_load(&(*self.regs).csr1)},
            Peripheral::Peripheral2 => unsafe {volatile_load(&(*self.regs).csr2)},
            Peripheral::Peripheral3 => unsafe {volatile_load(&(*self.regs).csr3)},
        }
    }
    /// Sets the Chip Select Register (CSR) of the active peripheral
    /// (CSR0, CSR1, CSR2, or CSR3).
    fn write_active_csr(&self, value: u32) {
        match self.get_active_peripheral() {
            Peripheral::Peripheral0 => unsafe {volatile_store(&mut (*self.regs).csr0, value)},
            Peripheral::Peripheral1 => unsafe {volatile_store(&mut (*self.regs).csr1, value)},
            Peripheral::Peripheral2 => unsafe {volatile_store(&mut (*self.regs).csr2, value)},
            Peripheral::Peripheral3 => unsafe {volatile_store(&mut (*self.regs).csr3, value)},
        };
    }

    /// Set the DMA channels used for reading and writing.
    pub fn set_dma(&mut self, read: &'static mut DMAChannel, write: &'static mut DMAChannel) {
        self.dma_read = Some(read);
        self.dma_write = Some(write);
    }
}

impl spi_master::SpiMaster for Spi {
    /// By default, initialize SPI to operate at 40KHz, clock is
    /// idle on low, and sample on the leading edge.
    fn init(&mut self, callback: &'static SpiCallback) {
        self.callback = Some(callback);
        self.set_rate(40000); // Set initial baud rate to 8MHz
        self.set_clock(ClockPolarity::IdleLow);
        self.set_phase(ClockPhase::SampleLeading);

        // Keep slave select active until a last transfer bit is set
        let mut csr = self.read_active_csr();
        csr |= 1 << 3;
        self.write_active_csr(csr);

        // Indicate the last transfer to disable slave select
        unsafe {volatile_store(&mut (*self.regs).cr, 1 << 24)};

        let mut mode = unsafe {volatile_load(&(*self.regs).mr)};
        mode |= 1; // Enable master mode
        mode |= 1 << 4; // Disable mode fault detection (open drain outputs not supported)
        unsafe {volatile_store(&mut (*self.regs).mr, mode)};

    }

    fn is_busy(&self) -> bool {
        self.reading.get() || self.writing.get()
    }

    /// Write a byte to the SPI and return the read; if an
    /// asynchronous operation is outstanding, do nothing.
    fn read_write_byte(&self, val: u8) -> u8 {
        if self.reading.get() || self.writing.get() {
  //          return 0;
        }
        self.write_byte(val);
        // Wait for receive data register full
        while (unsafe {volatile_load(&(*self.regs).sr)} & 1) != 1 {}
        // Return read value
        unsafe {volatile_load(&(*self.regs).rdr) as u8}
    }

    /// Write a byte to the SPI and discard the read; if an
    /// asynchronous operation is outstanding, do nothing.
    fn write_byte(&self, out_byte: u8) {
        if self.reading.get() || self.writing.get() {
 //           return;
        }
        let tdr = out_byte as u32;
        // Wait for data to leave TDR and enter serializer, so TDR is free
        // for this next byte
        while (unsafe {volatile_load(& (*self.regs).sr)} & 1 << 1) == 0 {}
        unsafe {volatile_store(&mut (*self.regs).tdr, tdr)};
    }

    /// Write 0 to the SPI and return the read; if an
    /// asynchronous operation is outstanding, do nothing.
    fn read_byte(&self) -> u8 {
        self.read_write_byte(0)
    }

    /// Asynchonous buffer read/write of SPI.
    /// write_buffer must  be Some; read_buffer may be None;
    /// if read_buffer is Some, then length of read/write is the
    /// minimum of two buffer lengths; returns true if operation
    /// starts (will receive callback through SpiClient), returns
    /// false if the operation does not start.
    // The write buffer has to be mutable because it's passed back to
    // the caller, and the caller may want to be able write into it.
    //
    // A better version of this would
    fn read_write_bytes(&self,
                        write_buffer:  Option<&'static mut [u8]>,
                        read_buffer: Option<&'static mut [u8]>,
                        len: usize) -> bool {
        let writing = write_buffer.is_some();
        let reading = read_buffer.is_some();
        // If there is no write buffer, or busy, then don't start.
        // Need to check self.reading as well as self.writing in case
        // write interrupt comes back first.
        if !writing  || self.reading.get() || self.writing.get() {
            return false
        }

        let pc18 = unsafe {&PC[18] as &hil::gpio::GPIOPin};
        pc18.toggle();
        // Need to mark if reading or writing so we correctly
        // regenerate Options on callback
        self.writing.set(writing);
        self.reading.set(reading);

        let read_len = match read_buffer {
            Some(ref buf) => {buf.len()},
            None          => 0
        };
        let write_len = match write_buffer {
            Some(ref buf) => {buf.len()},
            None          => 0
        };
        let buflen = if !reading {write_len}
                     else        {cmp::min(read_len, write_len)};
        let count = cmp::min(buflen, len);

        // The ordering of these operations matters; if you enable then
        // perform the operation, you can read a byte early on the SPI data register
        if reading {
            self.dma_read.as_ref().map(|read| read.do_xfer_buf(4, read_buffer, count));
        }
        self.dma_write.as_ref().map(|write| write.do_xfer_buf(22, write_buffer, count));
        if reading {
            self.dma_read.as_ref().map(|read| read.enable());
        }
        self.dma_write.as_ref().map(|write| write.enable());
        true
    }

    fn set_rate(&self, rate: u32) -> u32 {
        self.set_baud_rate(rate)
     }

    fn set_clock(&self, polarity: ClockPolarity) {
        let mut csr = self.read_active_csr();
        match polarity {
            ClockPolarity::IdleHigh => csr |= 1,
            ClockPolarity::IdleLow => csr &= 0xFFFFFFFE,
        };
        self.write_active_csr(csr);
    }

    fn set_phase(&self, phase: ClockPhase) {
        let mut csr = self.read_active_csr();
        match phase {
            ClockPhase::SampleLeading => csr |= 1 << 1,
            ClockPhase::SampleTrailing => csr &= 0xFFFFFFFD,
        };
        self.write_active_csr(csr);
    }

    fn set_chip_select(&self, cs: u8) -> bool{
        if cs >= 4 {
            return false
        }
        let peripheral_number: u32 = match cs {
            0 => 0b0000,
            1 => 0b0001,
            2 => 0b0011,
            3 => 0b0111,
            _ => 0b0000,
        };

        let mut mr = unsafe {volatile_load(&(*self.regs).mr)};
        // Clear and set MR.PCS
        let pcs_mask: u32 = 0xFFF0FFFF;
        mr &= pcs_mask;
        mr |= peripheral_number << 16;
        unsafe {volatile_store(&mut (*self.regs).mr, mr);}
        true
    }

    fn clear_chip_select(&self) {
       unsafe {volatile_store(&mut (*self.regs).cr, 1 << 24)};
    }
}

impl DMAClient for Spi {
    fn xfer_done(&mut self, pid: usize) {
        // I don't know if there are ordering guarantees on the read and
        // write interrupts, guessing not, so issue the callback when both
        // reading and writing are complete. In practice it seems like
        // the read interrupt happens second. -pal
        //
        // The disable calls are commented out because executing them
        // causes subsequent operations to fail. The call to read_write_bytes
        // calls enable(), so I don't know why. -pal
        if pid == 4  { // SPI RX
           // self.dma_read.as_ref().map(|dma| dma.disable());
            self.reading.set(false);
            if !self.reading.get() && !self.writing.get() {
                self.callback.as_ref().map(|cb| cb.read_write_done());
            }
        }
        if pid == 22 { // SPI TX
           // self.dma_write.as_ref().map(|dma| dma.disable());
            self.writing.set(false);
            if !self.reading.get() && !self.writing.get() {
                self.callback.as_ref().map(|cb| cb.read_write_done());
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::controls::{Adapted, Control, HasLabel};
use crate::types::{RecursiveTupleVecIterator};
use crate::sdk;
use crate::types::{adapter, Adapter, AsAny, RecursiveTupleVec, Spawnable};
use std::any::Any;
use std::marker::PhantomData;
use std::usize;

pub struct StringTupleVecAdapter<C: HasLabel + Spawnable> {
    item: RecursiveTupleVec<String>,
    on_item_change: Option<sdk::AdapterInnerCallback>,
    _marker: PhantomData<C>,
}
impl<C: HasLabel + Spawnable> StringTupleVecAdapter<C> {
    pub fn new() -> Self {
        Self::from(RecursiveTupleVec::default())
    }
}
impl<C: HasLabel + Spawnable> From<RecursiveTupleVec<String>> for StringTupleVecAdapter<C> {
    fn from(a: RecursiveTupleVec<String>) -> Self {
        StringTupleVecAdapter {
            item: a,
            on_item_change: None,
            _marker: PhantomData,
        }
    }
}
impl<C: HasLabel + Spawnable> AsAny for StringTupleVecAdapter<C> {
    #[inline]
    fn as_any(&self) -> &dyn Any {
        self
    }
    #[inline]
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
    #[inline]
    fn into_any(self: Box<Self>) -> Box<dyn Any> {
        self
    }
}

impl<C: HasLabel + Spawnable> Adapter for StringTupleVecAdapter<C> {
    fn len_at(&self, indexes: &[usize]) -> Option<usize> {
        if indexes.len() == 0 {
            if let Some(ref value) = self.item.value {
                Some(value.len())
            } else {
                None
            }
        } else {
            self.item.get(indexes).and_then(|n| n.value.as_ref()).map(|n| n.len())
        }
    }
    fn node_at(&self, indexes: &[usize]) -> Option<adapter::Node> {
        self.item.get(indexes).map(|n| if n.value.is_some() { adapter::Node::Branch(true) } else { adapter::Node::Leaf })
    }
    fn spawn_item_view(&mut self, indexes: &[usize], _: &dyn Adapted) -> Option<Box<dyn Control>> {
        self.item.get(indexes).map(|n| {
            let mut control = C::spawn();
            control.as_any_mut().downcast_mut::<C>().unwrap().set_label(n.id.as_str().into());

            control
        })
    }
    fn for_each<'a, 'b:'a, 'c: 'b>(&'c self, f: &'a mut dyn adapter::FnNodeItem) {
        let mut iterator = RecursiveTupleVecIterator::with_item(&self.item);
        while let Some((indexes, ref node, _item)) = iterator.next() {
            f(indexes, node);
        }
    }
}
impl<C: HasLabel + Spawnable> sdk::AdapterInner for StringTupleVecAdapter<C> {
    fn on_item_change(&mut self, cb: Option<sdk::AdapterInnerCallback>) {
        self.on_item_change = cb;
    }
}
<commit_msg>Modifyable StringTupleVecAdapter<commit_after>use crate::controls::{Adapted, Control, HasLabel};
use crate::types::{RecursiveTupleVecIterator};
use crate::sdk;
use crate::types::{adapter, Adapter, AsAny, RecursiveTupleVec, Spawnable};
use std::any::Any;
use std::marker::PhantomData;
use std::usize;

pub struct StringTupleVecAdapter<C: HasLabel + Spawnable> {
    item: RecursiveTupleVec<String>,
    on_item_change: Option<sdk::AdapterInnerCallback>,
    _marker: PhantomData<C>,
}
impl<C: HasLabel + Spawnable> StringTupleVecAdapter<C> {
    pub fn new() -> Self {
        Self::from(RecursiveTupleVec::default())
    }
    pub fn root(&self) -> &RecursiveTupleVec<String> {
    	&self.item
    }
    pub fn root_mut(&mut self) -> &mut RecursiveTupleVec<String> {
    	&mut self.item
    }
}
impl<C: HasLabel + Spawnable> From<RecursiveTupleVec<String>> for StringTupleVecAdapter<C> {
    fn from(a: RecursiveTupleVec<String>) -> Self {
        StringTupleVecAdapter {
            item: a,
            on_item_change: None,
            _marker: PhantomData,
        }
    }
}
impl<C: HasLabel + Spawnable> AsAny for StringTupleVecAdapter<C> {
    #[inline]
    fn as_any(&self) -> &dyn Any {
        self
    }
    #[inline]
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
    #[inline]
    fn into_any(self: Box<Self>) -> Box<dyn Any> {
        self
    }
}

impl<C: HasLabel + Spawnable> Adapter for StringTupleVecAdapter<C> {
    fn len_at(&self, indexes: &[usize]) -> Option<usize> {
        if indexes.len() == 0 {
            if let Some(ref value) = self.item.value {
                Some(value.len())
            } else {
                None
            }
        } else {
            self.item.get(indexes).and_then(|n| n.value.as_ref()).map(|n| n.len())
        }
    }
    fn node_at(&self, indexes: &[usize]) -> Option<adapter::Node> {
        self.item.get(indexes).map(|n| if n.value.is_some() { adapter::Node::Branch(true) } else { adapter::Node::Leaf })
    }
    fn spawn_item_view(&mut self, indexes: &[usize], _: &dyn Adapted) -> Option<Box<dyn Control>> {
        self.item.get(indexes).map(|n| {
            let mut control = C::spawn();
            control.as_any_mut().downcast_mut::<C>().unwrap().set_label(n.id.as_str().into());

            control
        })
    }
    fn for_each<'a, 'b:'a, 'c: 'b>(&'c self, f: &'a mut dyn adapter::FnNodeItem) {
        let mut iterator = RecursiveTupleVecIterator::with_item(&self.item);
        while let Some((indexes, ref node, _item)) = iterator.next() {
            f(indexes, node);
        }
    }
}
impl<C: HasLabel + Spawnable> sdk::AdapterInner for StringTupleVecAdapter<C> {
    fn on_item_change(&mut self, cb: Option<sdk::AdapterInnerCallback>) {
        self.on_item_change = cb;
    }
}
<|endoftext|>


<commit_before>use super::database::{id_to_class,class_to_type};

use self::parse_ebml_number::parse_ebml_number;
use self::parse_ebml_number::Result as EbmlParseNumberResult;
use self::parse_ebml_number::Mode   as EbmlParseNumberMode;

use std::vec::Vec;
use std::string::String;
use std::fmt;

mod parse_ebml_number;
#[cfg(test)] mod test;
pub mod debug;

extern crate byteorder;

#[derive(Eq,PartialEq,Clone)]
pub struct Info {
    pub id : u64,
    pub offset : u64,
    pub length_including_header : Option<u64>,
}

#[derive(Debug,PartialEq,Clone)]
pub enum SimpleContent<'a> {
    Unsigned(u64),
    Signed(i64),
    Text(&'a str),
    Binary(&'a [u8]),
    Float(f64),
    MatroskaDate(i64), // Nanoseconds since 20010101_000000_UTC

}
#[derive(Debug,PartialEq,Clone)]
pub enum Event<'a> {
    Begin(&'a Info),
    Data(SimpleContent<'a>),
    End(&'a Info),
    Resync,
}

pub trait EventsHandler {
    fn event(&mut self, e : Event);
}

pub trait Parser<'q, E : EventsHandler + ?Sized + 'q> {
    fn new(cb : &'q mut E) -> Self;
    fn feed_bytes(&mut self, bytes : &[u8]);
    fn force_resync(&mut self);
}

pub fn new<E : EventsHandler + ?Sized> (cb: &mut E) -> ParserState<E> {
    self::Parser::new(cb)
}

//////////////////////////////

impl fmt::Debug for Info {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result
    {
        let cl = super::database::id_to_class(self.id);
        let typ = super::database::class_to_type(cl);

        let cldesc = match cl {
            super::database::Class::Unknown => format!("0x{:X}", self.id),
            _ => format!("{:?}", cl),
        };

        let maybelen = match self.length_including_header {
            None => format!(""),
            Some(x) => format!(", rawlen:{}", x),
        };

        f.write_str(format!("{}(offset:{}{})", cldesc, self.offset, maybelen).as_str())
    }
}

enum ParserMode {
    Header,
    Data(usize, super::Type),
    Resync,
}

pub struct ParserState<'q, E : EventsHandler + ?Sized + 'q> {
    cb : &'q mut E,
    accumulator : Vec<u8>,
    opened_elements_stack : Vec<Info>,
    mode : ParserMode,
    current_offset : u64,
}

#[derive(Debug,Eq,PartialEq)]
enum ResultOfTryParseSomething<'a> {
    KeepGoing(&'a [u8]),
    NoMoreData,
    Error,
}

impl<'q, E:EventsHandler+?Sized+'q> ParserState<'q, E> {

    fn try_resync<'a>(&mut self, buf:&'a [u8]) -> ResultOfTryParseSomething<'a> {
        use self::ResultOfTryParseSomething::*;
        if buf.len() < 4 {
            return NoMoreData;
        }
        let (fourbytes, _) = buf.split_at(4);
        let id : u32 = (fourbytes[0] as u32)*0x1000000 + (fourbytes[1] as u32) * 0x10000 + (fourbytes[2] as u32) * 0x100 + (fourbytes[3] as u32);
        match id {
            0x1A45DFA3 | 0x18538067 | 0x1549A966 | 0x1F43B675 | 0x1654AE6B | 0x1C53BB6B | 0x1941A469 | 0x1043A770 | 0x1254C367
            => {
                self.mode = ParserMode::Header;
                KeepGoing(buf)
            }
            _ => {
                let (_, trail) = buf.split_at(1);
                KeepGoing(trail)
            }
        }
    }

    fn try_parse_element_data<'a>(&mut self, buf:&'a [u8], len:usize, typ : super::Type) -> ResultOfTryParseSomething<'a> {
        use self::ResultOfTryParseSomething::{NoMoreData,KeepGoing,Error};
        use self::Event::{Data};
        use self::SimpleContent::
                    {Unsigned, Signed, Text, Binary, Float, MatroskaDate};
        use self::ParserMode;

        if len <= buf.len() {
            self.mode = ParserMode::Header;
            let (l,r) = buf.split_at(len);
            let da = match typ {
                super::Type::Master => panic!("Wrong way"),
                super::Type::Binary => Binary(l),
                super::Type::Unsigned => {
                    let mut q : u64 = 0;
                    let mut it = l.iter();
                    if l.len() > 8 { return Error; }
                    loop {
                        match it.next() {
                            Some(x) => {q = q*0x100 + (*x as u64)},
                            None => break,
                        }
                    };
                    Unsigned(q)
                },
                super::Type::Signed | super::Type::Date => {
                    let mut q : i64 = 0;
                    let mut it = l.iter();
                    if l.len() > 8 { return Error; }
                    match it.next() {
                        Some(&x) if x >= 0x80 =>   { q = -(x as i64) + 0x80; },
                        Some(&x)              =>   { q = (x as i64); },
                        None => {},
                    }
                    loop {
                        match it.next() {
                            Some(&x) => {q = q*0x100 + (x as i64)},
                            None => break,
                        }
                    };
                    match typ {
                        super::Type::Signed => Signed(q),
                        super::Type::Date => MatroskaDate(q),
                        _ => panic!("Internal error"),
                    }
                },
                super::Type::TextAscii | super::Type::TextUtf8 => {
                    use std::str::from_utf8;
                    match from_utf8(l) {
                        Ok(x) => Text(x),
                        Err(_) => return Error,
                    }
                },
                super::Type::Float => {
                    use self::byteorder::ReadBytesExt;
                    use self::byteorder::BigEndian;
                    let mut ll = l;
                    match ll.len() {
                        8 =>
                            match ll.read_f64::<BigEndian>() {
                                Ok(x) => Float(x),
                                Err(_) => return Error,
                            },
                        4 =>
                            match ll.read_f32::<BigEndian>() {
                                Ok(x) => Float(x as f64),
                                Err(_) => return Error,
                            },
                        0 => Float(0.0),
                        10 => { error!("Error: 10-byte floats are not supported"); Binary(l) }
                        _ => return Error,
                    }
                }
            };
            self.cb.event( Data(da) );
            KeepGoing(r)
        } else {
            return NoMoreData;
        }
    }

    fn try_parse_element_header<'a>(&mut self, buf:&'a [u8]) -> ResultOfTryParseSomething<'a> {
        use self::ResultOfTryParseSomething::{NoMoreData,KeepGoing};
        use self::ResultOfTryParseSomething::Error as MyError;
        use self::parse_ebml_number::Result::*;
        use self::parse_ebml_number::Mode::*;
        use super::Type::{Master};
        use self::Event::{Begin};
        use self::ParserMode;

        let (r1, restbuf) = parse_ebml_number(buf, Identifier);
        let element_id = match r1 {
            Error => return MyError,
            NaN => return MyError,
            NotEnoughData => return NoMoreData,
            Ok(x) => x
        };

        let (r2, restbuf2) = parse_ebml_number(restbuf, Unsigned);

        let element_header_size = (buf.len() - restbuf2.len()) as u64;
        let element_size = match r2 {
            Error => return MyError,
            NaN => None,
            NotEnoughData => return NoMoreData,
            Ok(x) => Some(x)
        };
        let full_element_size = match element_size {
            None => None,
            Some(x) => Some(x + element_header_size),
        };

        let cl  = id_to_class(element_id);
        let typ = class_to_type(cl);

        let mut restbuf3 = restbuf2;

        self.mode = match typ {
            Master => ParserMode::Header,
            t => match element_size {
                None => ParserMode::Resync,
                Some(x) => ParserMode::Data(x as usize, t),
            }
        };

        let el = Info{id: element_id, length_including_header: full_element_size, offset: self.current_offset};
        self.cb.event( Begin( &el ));
        self.opened_elements_stack.push(el);
        //self.cb.auxilary_event( Debug (format!("element class={:?} type={:?} off={} clid={}  len={:?}",
        //                                                cl, typ, self.current_offset, element_id, element_size )));

        KeepGoing(restbuf3)
    }

    fn close_expired_elements<'a>(&mut self) {
        use self::Event::{End};
        let mut number_of_elements_to_remove = 0;

        for i in self.opened_elements_stack.iter().rev() {
            let retain = match i.length_including_header {
                None => true,
                Some(l) => i.offset + l > self.current_offset
            };
            // println!("dr {:?} {} -> {}", i, self.current_offset, retain);

            if retain {
                break;
            } else {
                number_of_elements_to_remove += 1;
            }
        }

        {
            let mut j = 0;
            for i in self.opened_elements_stack.iter().rev() {
                j += 1;
                if j > number_of_elements_to_remove { break; }
                // println!("sending end {:?}", i);
                self.cb.event (End(i));
            }
        }

        let newlen = self.opened_elements_stack.len() - number_of_elements_to_remove;
        self.opened_elements_stack.truncate(newlen);
    }
}

impl<'q, E : EventsHandler + ?Sized + 'q> Parser<'q, E> for ParserState<'q, E> {
    fn new(cb : &'q mut E) -> ParserState<'q, E> {
        ParserState {
            accumulator: vec![],
            cb : cb,
            mode : ParserMode::Header,
            opened_elements_stack : vec![],
            current_offset : 0,
        }
    }

    fn feed_bytes(&mut self, bytes : &[u8])
    {
        use self::ResultOfTryParseSomething::*;
        use self::ParserMode::*;

        //self.cb.log(format!("feed_bytes {} len={}", bytes[0], self.accumulator.len()).as_str() );
        self.accumulator.push_all(bytes);

        let tmpvector = self.accumulator.to_vec();
        {
            let mut buf = tmpvector.as_slice();
            //self.cb.log( format!("feed_bytes2 len={} buflen={}", self.accumulator.len(), buf.len()) );
            loop {
                let r = match self.mode {
                    Resync => self.try_resync(buf),
                    Header => self.try_parse_element_header(buf),
                    Data(x, t) => self.try_parse_element_data(buf, x, t),
                };
                //self.cb.log( format!("try_parse_something={:?}", r));
                let newbuf = match r {
                    NoMoreData => break,
                    Error => {self.mode = ParserMode::Resync; self.cb.event(self::Event::Resync); buf},
                    KeepGoing(rest) => rest
                };
                self.current_offset += (buf.len() - newbuf.len()) as u64;
                //self.cb.log(format!("current offset: {}", self.current_offset).as_str());

                if let KeepGoing(_) = r {
                    if let Data(0, t) = self.mode {
                        self.try_parse_element_data(newbuf, 0, t);
                    };
                };

                self.close_expired_elements();
                buf = newbuf;
                //self.cb.log(format!("more to parse: {}", newbuf.len()).as_str());
            }
            self.accumulator = buf.to_vec();
        }
        //self.cb.log( format!("feed_bytes3 len={}" , self.accumulator.len()).as_str());
    }

    fn force_resync(&mut self)
    {
        self.mode = self::ParserMode::Resync;
    }
}
<commit_msg>Actualise<commit_after>use super::database::{id_to_class,class_to_type};

use self::parse_ebml_number::parse_ebml_number;
use self::parse_ebml_number::Result as EbmlParseNumberResult;
use self::parse_ebml_number::Mode   as EbmlParseNumberMode;

use std::vec::Vec;
use std::string::String;
use std::fmt;

mod parse_ebml_number;
#[cfg(test)] mod test;
pub mod debug;

extern crate byteorder;

#[derive(Eq,PartialEq,Clone)]
pub struct Info {
    pub id : u64,
    pub offset : u64,
    pub length_including_header : Option<u64>,
}

#[derive(Debug,PartialEq,Clone)]
pub enum SimpleContent<'a> {
    Unsigned(u64),
    Signed(i64),
    Text(&'a str),
    Binary(&'a [u8]),
    Float(f64),
    MatroskaDate(i64), // Nanoseconds since 20010101_000000_UTC

}
#[derive(Debug,PartialEq,Clone)]
pub enum Event<'a> {
    Begin(&'a Info),
    Data(SimpleContent<'a>),
    End(&'a Info),
    Resync,
}

pub trait EventsHandler {
    fn event(&mut self, e : Event);
}

pub trait Parser<'q, E : EventsHandler + ?Sized + 'q> {
    fn new(cb : &'q mut E) -> Self;
    fn feed_bytes(&mut self, bytes : &[u8]);
    fn force_resync(&mut self);
}

pub fn new<E : EventsHandler + ?Sized> (cb: &mut E) -> ParserState<E> {
    self::Parser::new(cb)
}

//////////////////////////////

impl fmt::Debug for Info {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result
    {
        let cl = super::database::id_to_class(self.id);
        let typ = super::database::class_to_type(cl);

        let cldesc = match cl {
            super::database::Class::Unknown => format!("0x{:X}", self.id),
            _ => format!("{:?}", cl),
        };

        let maybelen = match self.length_including_header {
            None => format!(""),
            Some(x) => format!(", rawlen:{}", x),
        };

        f.write_str(format!("{}(offset:{}{})", cldesc, self.offset, maybelen).as_str())
    }
}

enum ParserMode {
    Header,
    Data(usize, super::Type),
    Resync,
}

pub struct ParserState<'q, E : EventsHandler + ?Sized + 'q> {
    cb : &'q mut E,
    accumulator : Vec<u8>,
    opened_elements_stack : Vec<Info>,
    mode : ParserMode,
    current_offset : u64,
}

#[derive(Debug,Eq,PartialEq)]
enum ResultOfTryParseSomething<'a> {
    KeepGoing(&'a [u8]),
    NoMoreData,
    Error,
}

impl<'q, E:EventsHandler+?Sized+'q> ParserState<'q, E> {

    fn try_resync<'a>(&mut self, buf:&'a [u8]) -> ResultOfTryParseSomething<'a> {
        use self::ResultOfTryParseSomething::*;
        if buf.len() < 4 {
            return NoMoreData;
        }
        let (fourbytes, _) = buf.split_at(4);
        let id : u32 = (fourbytes[0] as u32)*0x1000000 + (fourbytes[1] as u32) * 0x10000 + (fourbytes[2] as u32) * 0x100 + (fourbytes[3] as u32);
        match id {
            0x1A45DFA3 | 0x18538067 | 0x1549A966 | 0x1F43B675 | 0x1654AE6B | 0x1C53BB6B | 0x1941A469 | 0x1043A770 | 0x1254C367
            => {
                self.mode = ParserMode::Header;
                KeepGoing(buf)
            }
            _ => {
                let (_, trail) = buf.split_at(1);
                KeepGoing(trail)
            }
        }
    }

    fn try_parse_element_data<'a>(&mut self, buf:&'a [u8], len:usize, typ : super::Type) -> ResultOfTryParseSomething<'a> {
        use self::ResultOfTryParseSomething::{NoMoreData,KeepGoing,Error};
        use self::Event::{Data};
        use self::SimpleContent::
                    {Unsigned, Signed, Text, Binary, Float, MatroskaDate};
        use self::ParserMode;

        if len <= buf.len() {
            self.mode = ParserMode::Header;
            let (l,r) = buf.split_at(len);
            let da = match typ {
                super::Type::Master => panic!("Wrong way"),
                super::Type::Binary => Binary(l),
                super::Type::Unsigned => {
                    let mut q : u64 = 0;
                    let mut it = l.iter();
                    if l.len() > 8 { return Error; }
                    loop {
                        match it.next() {
                            Some(x) => {q = q*0x100 + (*x as u64)},
                            None => break,
                        }
                    };
                    Unsigned(q)
                },
                super::Type::Signed | super::Type::Date => {
                    let mut q : i64 = 0;
                    let mut it = l.iter();
                    if l.len() > 8 { return Error; }
                    match it.next() {
                        Some(&x) if x >= 0x80 =>   { q = -(x as i64) + 0x80; },
                        Some(&x)              =>   { q = (x as i64); },
                        None => {},
                    }
                    loop {
                        match it.next() {
                            Some(&x) => {q = q*0x100 + (x as i64)},
                            None => break,
                        }
                    };
                    match typ {
                        super::Type::Signed => Signed(q),
                        super::Type::Date => MatroskaDate(q),
                        _ => panic!("Internal error"),
                    }
                },
                super::Type::TextAscii | super::Type::TextUtf8 => {
                    use std::str::from_utf8;
                    match from_utf8(l) {
                        Ok(x) => Text(x),
                        Err(_) => return Error,
                    }
                },
                super::Type::Float => {
                    use self::byteorder::ReadBytesExt;
                    use self::byteorder::BigEndian;
                    let mut ll = l;
                    match ll.len() {
                        8 =>
                            match ll.read_f64::<BigEndian>() {
                                Ok(x) => Float(x),
                                Err(_) => return Error,
                            },
                        4 =>
                            match ll.read_f32::<BigEndian>() {
                                Ok(x) => Float(x as f64),
                                Err(_) => return Error,
                            },
                        0 => Float(0.0),
                        10 => { error!("Error: 10-byte floats are not supported"); Binary(l) }
                        _ => return Error,
                    }
                }
            };
            self.cb.event( Data(da) );
            KeepGoing(r)
        } else {
            return NoMoreData;
        }
    }

    fn try_parse_element_header<'a>(&mut self, buf:&'a [u8]) -> ResultOfTryParseSomething<'a> {
        use self::ResultOfTryParseSomething::{NoMoreData,KeepGoing};
        use self::ResultOfTryParseSomething::Error as MyError;
        use self::parse_ebml_number::Result::*;
        use self::parse_ebml_number::Mode::*;
        use super::Type::{Master};
        use self::Event::{Begin};
        use self::ParserMode;

        let (r1, restbuf) = parse_ebml_number(buf, Identifier);
        let element_id = match r1 {
            Error => return MyError,
            NaN => return MyError,
            NotEnoughData => return NoMoreData,
            Ok(x) => x
        };

        let (r2, restbuf2) = parse_ebml_number(restbuf, Unsigned);

        let element_header_size = (buf.len() - restbuf2.len()) as u64;
        let element_size = match r2 {
            Error => return MyError,
            NaN => None,
            NotEnoughData => return NoMoreData,
            Ok(x) => Some(x)
        };
        let full_element_size = match element_size {
            None => None,
            Some(x) => Some(x + element_header_size),
        };

        let cl  = id_to_class(element_id);
        let typ = class_to_type(cl);

        let mut restbuf3 = restbuf2;

        self.mode = match typ {
            Master => ParserMode::Header,
            t => match element_size {
                None => ParserMode::Resync,
                Some(x) => ParserMode::Data(x as usize, t),
            }
        };

        let el = Info{id: element_id, length_including_header: full_element_size, offset: self.current_offset};
        self.cb.event( Begin( &el ));
        self.opened_elements_stack.push(el);
        //self.cb.auxilary_event( Debug (format!("element class={:?} type={:?} off={} clid={}  len={:?}",
        //                                                cl, typ, self.current_offset, element_id, element_size )));

        KeepGoing(restbuf3)
    }

    fn close_expired_elements<'a>(&mut self) {
        use self::Event::{End};
        let mut number_of_elements_to_remove = 0;

        for i in self.opened_elements_stack.iter().rev() {
            let retain = match i.length_including_header {
                None => true,
                Some(l) => i.offset + l > self.current_offset
            };
            // println!("dr {:?} {} -> {}", i, self.current_offset, retain);

            if retain {
                break;
            } else {
                number_of_elements_to_remove += 1;
            }
        }

        {
            let mut j = 0;
            for i in self.opened_elements_stack.iter().rev() {
                j += 1;
                if j > number_of_elements_to_remove { break; }
                // println!("sending end {:?}", i);
                self.cb.event (End(i));
            }
        }

        let newlen = self.opened_elements_stack.len() - number_of_elements_to_remove;
        self.opened_elements_stack.truncate(newlen);
    }
}

impl<'q, E : EventsHandler + ?Sized + 'q> Parser<'q, E> for ParserState<'q, E> {
    fn new(cb : &'q mut E) -> ParserState<'q, E> {
        ParserState {
            accumulator: vec![],
            cb : cb,
            mode : ParserMode::Header,
            opened_elements_stack : vec![],
            current_offset : 0,
        }
    }

    fn feed_bytes(&mut self, bytes : &[u8])
    {
        use self::ResultOfTryParseSomething::*;
        use self::ParserMode::*;

        //self.cb.log(format!("feed_bytes {} len={}", bytes[0], self.accumulator.len()).as_str() );
        self.accumulator.extend_from_slice(bytes);

        let tmpvector = self.accumulator.to_vec();
        {
            let mut buf = tmpvector.as_slice();
            //self.cb.log( format!("feed_bytes2 len={} buflen={}", self.accumulator.len(), buf.len()) );
            loop {
                let r = match self.mode {
                    Resync => self.try_resync(buf),
                    Header => self.try_parse_element_header(buf),
                    Data(x, t) => self.try_parse_element_data(buf, x, t),
                };
                //self.cb.log( format!("try_parse_something={:?}", r));
                let newbuf = match r {
                    NoMoreData => break,
                    Error => {self.mode = ParserMode::Resync; self.cb.event(self::Event::Resync); buf},
                    KeepGoing(rest) => rest
                };
                self.current_offset += (buf.len() - newbuf.len()) as u64;
                //self.cb.log(format!("current offset: {}", self.current_offset).as_str());

                if let KeepGoing(_) = r {
                    if let Data(0, t) = self.mode {
                        self.try_parse_element_data(newbuf, 0, t);
                    };
                };

                self.close_expired_elements();
                buf = newbuf;
                //self.cb.log(format!("more to parse: {}", newbuf.len()).as_str());
            }
            self.accumulator = buf.to_vec();
        }
        //self.cb.log( format!("feed_bytes3 len={}" , self.accumulator.len()).as_str());
    }

    fn force_resync(&mut self)
    {
        self.mode = self::ParserMode::Resync;
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin_registrar, rustc_private)]

extern crate syntax;
extern crate syntax_ext;
extern crate rustc_plugin;

use syntax::ast::{MetaItem, Expr};
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax_ext::deriving::generic::*;
use syntax_ext::deriving::generic::ty::*;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::ext::base::MultiDecorator;
use syntax::parse::token;

use rustc_plugin::Registry;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::syntax_ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::syntax_ext::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                      span: Span,
                                      mitem: &MetaItem,
                                      item: &Annotatable,
                                      push: &mut FnMut(Annotatable))
{
    let inline = cx.meta_word(span, InternedString::new("inline"));
    let attrs = vec!(cx.attribute(span, inline));
    let trait_def = TraitDef {
        is_unsafe: false,
        span: span,
        attributes: Vec::new(),
        path: path!(num::FromPrimitive),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "from_i64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(i64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs.clone(),
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("i64", c, s, sub)
                })),
            },
            MethodDef {
                name: "from_u64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(u64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs,
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("u64", c, s, sub)
                })),
            }
        ),
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, mitem, &item, push)
}

fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    if substr.nonself_args.len() != 1 {
        cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
    }

    let n = &substr.nonself_args[0];

    match *substr.fields {
        StaticStruct(..) => {
            cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
            return cx.expr_fail(trait_span, InternedString::new(""));
        }
        StaticEnum(enum_def, _) => {
            if enum_def.variants.is_empty() {
                cx.span_err(trait_span,
                            "`FromPrimitive` cannot be derived for enums with no variants");
                return cx.expr_fail(trait_span, InternedString::new(""));
            }

            let mut arms = Vec::new();

            for variant in &enum_def.variants {
                match variant.node.data {
                    ast::VariantData::Unit(..) => {
                        let span = variant.span;

                        // expr for `$n == $variant as $name`
                        let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
                        let variant = cx.expr_path(path);
                        let ty = cx.ty_ident(span, cx.ident_of(name));
                        let cast = cx.expr_cast(span, variant.clone(), ty);
                        let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);

                        // expr for `Some($variant)`
                        let body = cx.expr_some(span, variant);

                        // arm for `_ if $guard => $body`
                        let arm = ast::Arm {
                            attrs: vec!(),
                            pats: vec!(cx.pat_wild(span)),
                            guard: Some(guard),
                            body: body,
                        };

                        arms.push(arm);
                    }
                    ast::VariantData::Tuple(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for \
                                    enum variants with arguments");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                    ast::VariantData::Struct(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for enums \
                                    with struct variants");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                }
            }

            // arm for `_ => None`
            let arm = ast::Arm {
                attrs: vec!(),
                pats: vec!(cx.pat_wild(trait_span)),
                guard: None,
                body: cx.expr_none(trait_span),
            };
            arms.push(arm);

            cx.expr_match(trait_span, n.clone(), arms)
        }
        _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("derive_NumFromPrimitive"),
        MultiDecorator(Box::new(expand_deriving_from_primitive)));
}
<commit_msg>Auto merge of #163 - gmorenz:update_nightly, r=hauleth<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin_registrar, rustc_private)]

extern crate syntax;
extern crate syntax_ext;
extern crate rustc_plugin;

use syntax::ast::{MetaItem, Expr, BinOpKind};
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax_ext::deriving::generic::*;
use syntax_ext::deriving::generic::ty::*;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::ext::base::MultiDecorator;
use syntax::parse::token;

use rustc_plugin::Registry;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::syntax_ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::syntax_ext::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                      span: Span,
                                      mitem: &MetaItem,
                                      item: &Annotatable,
                                      push: &mut FnMut(Annotatable))
{
    let inline = cx.meta_word(span, InternedString::new("inline"));
    let attrs = vec!(cx.attribute(span, inline));
    let trait_def = TraitDef {
        is_unsafe: false,
        span: span,
        attributes: Vec::new(),
        path: path!(num::FromPrimitive),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "from_i64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(i64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs.clone(),
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("i64", c, s, sub)
                })),
            },
            MethodDef {
                name: "from_u64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(u64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs,
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("u64", c, s, sub)
                })),
            }
        ),
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, mitem, &item, push)
}

fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    if substr.nonself_args.len() != 1 {
        cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
    }

    let n = &substr.nonself_args[0];

    match *substr.fields {
        StaticStruct(..) => {
            cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
            return cx.expr_fail(trait_span, InternedString::new(""));
        }
        StaticEnum(enum_def, _) => {
            if enum_def.variants.is_empty() {
                cx.span_err(trait_span,
                            "`FromPrimitive` cannot be derived for enums with no variants");
                return cx.expr_fail(trait_span, InternedString::new(""));
            }

            let mut arms = Vec::new();

            for variant in &enum_def.variants {
                match variant.node.data {
                    ast::VariantData::Unit(..) => {
                        let span = variant.span;

                        // expr for `$n == $variant as $name`
                        let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
                        let variant = cx.expr_path(path);
                        let ty = cx.ty_ident(span, cx.ident_of(name));
                        let cast = cx.expr_cast(span, variant.clone(), ty);
                        let guard = cx.expr_binary(span, BinOpKind::Eq, n.clone(), cast);

                        // expr for `Some($variant)`
                        let body = cx.expr_some(span, variant);

                        // arm for `_ if $guard => $body`
                        let arm = ast::Arm {
                            attrs: vec!(),
                            pats: vec!(cx.pat_wild(span)),
                            guard: Some(guard),
                            body: body,
                        };

                        arms.push(arm);
                    }
                    ast::VariantData::Tuple(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for \
                                    enum variants with arguments");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                    ast::VariantData::Struct(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for enums \
                                    with struct variants");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                }
            }

            // arm for `_ => None`
            let arm = ast::Arm {
                attrs: vec!(),
                pats: vec!(cx.pat_wild(trait_span)),
                guard: None,
                body: cx.expr_none(trait_span),
            };
            arms.push(arm);

            cx.expr_match(trait_span, n.clone(), arms)
        }
        _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("derive_NumFromPrimitive"),
        MultiDecorator(Box::new(expand_deriving_from_primitive)));
}
<|endoftext|>


<commit_before>use serde_json::value::Value as Json;

use crate::context::{BlockParams, Context};
use crate::error::RenderError;
use crate::helpers::{HelperDef, HelperResult};
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext, Renderable};
use crate::value::{to_json, JsonTruthy};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry,
        ctx: &Context,
        rc: &mut RenderContext<'reg>,
        out: &mut Output,
    ) -> HelperResult {
        let value = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"each\""))?;

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                let local_path_root = value
                    .path_root()
                    .map(|p| format!("{}/{}", rc.get_path(), p));

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(false), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for (i, _) in list.iter().enumerate().take(len) {
                            let mut local_rc = rc.derive();
                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }

                            local_rc.set_local_var("@first".to_string(), to_json(i == 0usize));
                            local_rc.set_local_var("@last".to_string(), to_json(i == len - 1));
                            local_rc.set_local_var("@index".to_string(), to_json(i));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, i);
                                debug!("each path {:?}", new_path);
                                local_rc.set_path(new_path);
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut params = BlockParams::new();
                                // TODO: this or "[i]"
                                params.add_path(block_param, &format!("[{}]", i))?;

                                local_rc.push_block_context(params);
                            }

                            t.render(r, ctx, &mut local_rc, out)?;

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for (k, v) in obj.iter() {
                            let mut local_rc = rc.derive();

                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }
                            local_rc.set_local_var("@first".to_string(), to_json(first));
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), to_json(k));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, k);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_val, bp_key)) = h.block_param_pair() {
                                let mut params = BlockParams::new();
                                params.add_path(bp_val, &format!("{}", k))?;
                                params.add_value(bp_key, to_json(&k));

                                local_rc.push_block_context(params)?;
                            }

                            t.render(r, ctx, &mut local_rc, out)?;

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            else_template.render(r, ctx, rc, out)?;
                        }
                        Ok(())
                    }
                    _ => Err(RenderError::new(format!(
                        "Param type is not iterable: {:?}",
                        value.value()
                    ))),
                };

                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use crate::registry::Registry;
    use crate::value::to_json;

    use serde_json::value::Value as Json;
    use std::collections::BTreeMap;
    use std::str::FromStr;

    #[test]
    fn test_each() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}")
            .is_ok());

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(
            r0.ok().unwrap(),
            "true|false|0:1|false|false|1:2|false|true|2:3|".to_string()
        );

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_each_with_parent() {
        let json_str = r#"{"a":{"a":99,"c":[{"d":100},{"d":200}]}}"#;

        let data = Json::from_str(json_str).unwrap();
        // println!("data: {}", data);
        let mut handlebars = Registry::new();

        // previously, to access the parent in an each block,
        // a user would need to specify ../../b, as the path
        // that is computed includes the array index: ./a.c.[0]
        assert!(handlebars
            .register_template_string("t0", "{{#each a.c}} d={{d}} b={{../a.a}} {{/each}}")
            .is_ok());

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), " d=100 b=99  d=200 b=99 ".to_string());
    }

    #[test]
    fn test_nested_each_with_parent() {
        let json_str = r#"{"a": [{"b": [{"d": 100}], "c": 200}]}"#;

        let data = Json::from_str(json_str).unwrap();
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each a}}{{#each b}}{{d}}:{{../c}}{{/each}}{{/each}}"
            )
            .is_ok());

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "100:200".to_string());
    }

    #[test]
    fn test_nested_each() {
        let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

        let data = Json::from_str(json_str).unwrap();

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}"
            )
            .is_ok());

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "12345".to_string());
    }

    #[test]
    fn test_nested_array() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each this.[0]}}{{this}}{{/each}}")
            .is_ok());

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each this}}{{@key}}-{{value}}\n{{/each}}")
            .is_ok());

        let r0 = handlebars
            .render(
                "t0",
                &({
                    let mut rv = BTreeMap::new();
                    rv.insert("foo".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "bar".to_owned());
                        rv
                    });
                    rv.insert("".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "baz".to_owned());
                        rv
                    });
                    rv
                }),
            )
            .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }

    #[test]
    fn test_each_else() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each a}}1{{else}}empty{{/each}}")
            .is_ok());
        let m1 = btreemap! {
            "a".to_string() => Vec::<String>::new(),
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "empty");

        let m2 = btreemap! {
            "b".to_string() => Vec::<String>::new()
        };
        let r1 = handlebars.render("t0", &m2).unwrap();
        assert_eq!(r1, "empty");
    }

    #[test]
    fn test_block_param() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each a as |i|}}{{i}}{{/each}}")
            .is_ok());
        let m1 = btreemap! {
            "a".to_string() => vec![1,2,3,4,5]
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "12345");
    }

    #[test]
    fn test_each_object_block_param() {
        let mut handlebars = Registry::new();
        let template = "{{#each this as |v k|}}\
                        {{#with k as |inner_k|}}{{inner_k}}{{/with}}:{{v}}|\
                        {{/each}}";
        assert!(handlebars.register_template_string("t0", template).is_ok());

        let m = btreemap! {
            "ftp".to_string() => 21,
            "http".to_string() => 80
        };
        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "ftp:21|http:80|".to_string());
    }

    #[test]
    fn test_nested_each_with_path_ups() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each a.b}}{{#each c}}{{../../d}}{{/each}}{{/each}}"
            )
            .is_ok());

        let data = btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(&1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());
    }

    #[test]
    fn test_nested_each_with_path_up_this() {
        let mut handlebars = Registry::new();
        let template = "{{#each variant}}{{#each ../typearg}}\
                        {{#if @first}}template<{{/if}}{{this}}{{#if @last}}>{{else}},{{/if}}\
                        {{/each}}{{/each}}";
        assert!(handlebars.register_template_string("t0", template).is_ok());
        let data = btreemap! {
            "typearg".to_string() => vec!["T".to_string()],
            "variant".to_string() => vec!["1".to_string(), "2".to_string()]
        };
        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "template<T>template<T>".to_string());
    }

    #[test]
    fn test_key_iteration_with_unicode() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each this}}{{@key}}: {{this}}\n{{/each}}")
            .is_ok());
        let data = json!({
            "normal": 1,
            "你好": 2,
            "#special key": 3,
            "😂": 4,
            "me.dot.key": 5
        });
        let r0 = handlebars.render("t0", &data).ok().unwrap();
        assert!(r0.contains("normal: 1"));
        assert!(r0.contains("你好: 2"));
        assert!(r0.contains("#special key: 3"));
        assert!(r0.contains("😂: 4"));
        assert!(r0.contains("me.dot.key: 5"));
    }
}
<commit_msg>(fix) unused variables<commit_after>use serde_json::value::Value as Json;

use crate::context::{BlockParams, Context};
use crate::error::RenderError;
use crate::helpers::{HelperDef, HelperResult};
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext, Renderable};
use crate::value::{to_json, JsonTruthy};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry,
        ctx: &Context,
        rc: &mut RenderContext<'reg>,
        out: &mut Output,
    ) -> HelperResult {
        let value = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"each\""))?;

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                let local_path_root = value
                    .path_root()
                    .map(|p| format!("{}/{}", rc.get_path(), p));

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(false), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for (i, _) in list.iter().enumerate().take(len) {
                            let mut local_rc = rc.derive();
                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }

                            local_rc.set_local_var("@first".to_string(), to_json(i == 0usize));
                            local_rc.set_local_var("@last".to_string(), to_json(i == len - 1));
                            local_rc.set_local_var("@index".to_string(), to_json(i));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, i);
                                debug!("each path {:?}", new_path);
                                local_rc.set_path(new_path);
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut params = BlockParams::new();
                                // TODO: this or "[i]"
                                params.add_path(block_param, &format!("[{}]", i))?;

                                local_rc.push_block_context(params);
                            }

                            t.render(r, ctx, &mut local_rc, out)?;

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for (k, _) in obj.iter() {
                            let mut local_rc = rc.derive();

                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }
                            local_rc.set_local_var("@first".to_string(), to_json(first));
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), to_json(k));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, k);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_val, bp_key)) = h.block_param_pair() {
                                let mut params = BlockParams::new();
                                params.add_path(bp_val, &format!("{}", k))?;
                                params.add_value(bp_key, to_json(&k));

                                local_rc.push_block_context(params)?;
                            }

                            t.render(r, ctx, &mut local_rc, out)?;

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            else_template.render(r, ctx, rc, out)?;
                        }
                        Ok(())
                    }
                    _ => Err(RenderError::new(format!(
                        "Param type is not iterable: {:?}",
                        value.value()
                    ))),
                };

                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use crate::registry::Registry;
    use crate::value::to_json;

    use serde_json::value::Value as Json;
    use std::collections::BTreeMap;
    use std::str::FromStr;

    #[test]
    fn test_each() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}")
            .is_ok());

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(
            r0.ok().unwrap(),
            "true|false|0:1|false|false|1:2|false|true|2:3|".to_string()
        );

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_each_with_parent() {
        let json_str = r#"{"a":{"a":99,"c":[{"d":100},{"d":200}]}}"#;

        let data = Json::from_str(json_str).unwrap();
        // println!("data: {}", data);
        let mut handlebars = Registry::new();

        // previously, to access the parent in an each block,
        // a user would need to specify ../../b, as the path
        // that is computed includes the array index: ./a.c.[0]
        assert!(handlebars
            .register_template_string("t0", "{{#each a.c}} d={{d}} b={{../a.a}} {{/each}}")
            .is_ok());

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), " d=100 b=99  d=200 b=99 ".to_string());
    }

    #[test]
    fn test_nested_each_with_parent() {
        let json_str = r#"{"a": [{"b": [{"d": 100}], "c": 200}]}"#;

        let data = Json::from_str(json_str).unwrap();
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each a}}{{#each b}}{{d}}:{{../c}}{{/each}}{{/each}}"
            )
            .is_ok());

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "100:200".to_string());
    }

    #[test]
    fn test_nested_each() {
        let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

        let data = Json::from_str(json_str).unwrap();

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}"
            )
            .is_ok());

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "12345".to_string());
    }

    #[test]
    fn test_nested_array() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each this.[0]}}{{this}}{{/each}}")
            .is_ok());

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each this}}{{@key}}-{{value}}\n{{/each}}")
            .is_ok());

        let r0 = handlebars
            .render(
                "t0",
                &({
                    let mut rv = BTreeMap::new();
                    rv.insert("foo".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "bar".to_owned());
                        rv
                    });
                    rv.insert("".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "baz".to_owned());
                        rv
                    });
                    rv
                }),
            )
            .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }

    #[test]
    fn test_each_else() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each a}}1{{else}}empty{{/each}}")
            .is_ok());
        let m1 = btreemap! {
            "a".to_string() => Vec::<String>::new(),
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "empty");

        let m2 = btreemap! {
            "b".to_string() => Vec::<String>::new()
        };
        let r1 = handlebars.render("t0", &m2).unwrap();
        assert_eq!(r1, "empty");
    }

    #[test]
    fn test_block_param() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each a as |i|}}{{i}}{{/each}}")
            .is_ok());
        let m1 = btreemap! {
            "a".to_string() => vec![1,2,3,4,5]
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "12345");
    }

    #[test]
    fn test_each_object_block_param() {
        let mut handlebars = Registry::new();
        let template = "{{#each this as |v k|}}\
                        {{#with k as |inner_k|}}{{inner_k}}{{/with}}:{{v}}|\
                        {{/each}}";
        assert!(handlebars.register_template_string("t0", template).is_ok());

        let m = btreemap! {
            "ftp".to_string() => 21,
            "http".to_string() => 80
        };
        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "ftp:21|http:80|".to_string());
    }

    #[test]
    fn test_nested_each_with_path_ups() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each a.b}}{{#each c}}{{../../d}}{{/each}}{{/each}}"
            )
            .is_ok());

        let data = btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(&1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());
    }

    #[test]
    fn test_nested_each_with_path_up_this() {
        let mut handlebars = Registry::new();
        let template = "{{#each variant}}{{#each ../typearg}}\
                        {{#if @first}}template<{{/if}}{{this}}{{#if @last}}>{{else}},{{/if}}\
                        {{/each}}{{/each}}";
        assert!(handlebars.register_template_string("t0", template).is_ok());
        let data = btreemap! {
            "typearg".to_string() => vec!["T".to_string()],
            "variant".to_string() => vec!["1".to_string(), "2".to_string()]
        };
        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "template<T>template<T>".to_string());
    }

    #[test]
    fn test_key_iteration_with_unicode() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#each this}}{{@key}}: {{this}}\n{{/each}}")
            .is_ok());
        let data = json!({
            "normal": 1,
            "你好": 2,
            "#special key": 3,
            "😂": 4,
            "me.dot.key": 5
        });
        let r0 = handlebars.render("t0", &data).ok().unwrap();
        assert!(r0.contains("normal: 1"));
        assert!(r0.contains("你好: 2"));
        assert!(r0.contains("#special key: 3"));
        assert!(r0.contains("😂: 4"));
        assert!(r0.contains("me.dot.key: 5"));
    }
}
<|endoftext|>