<commit_before>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use cache::cache::Cache;
use std::fs::File;
use std::fs;
use std::io::{Read,Write};
use std::io;
use std::path::Path;

pub struct Filecache {
    pub basepath: String,
}

impl Filecache {
    fn dir(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16) -> String {
        format!("{}/{}/{}", self.basepath, zoom, xtile)
    }
    fn path(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16) -> String {
        format!("{}/{}.pbf", self.dir(tileset, xtile, ytile, zoom), ytile)
    }
}

impl Cache for Filecache {
    fn lookup<F>(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16, mut read: F) -> Result<(), io::Error>
        where F : FnMut(&mut Read) -> Result<(), io::Error>
    {
        match File::open(&self.path(tileset, xtile, ytile, zoom)) {
            Ok(mut f) => read(&mut f),
            Err(e) => Err(e)
        }
    }
    fn store<F>(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16, mut write: F) -> Result<(), io::Error>
        where F : Fn(&mut Write) -> Result<(), io::Error>
    {
        let dir = self.dir(tileset, xtile, ytile, zoom);
        try!(fs::create_dir_all(Path::new(&dir as &str)));
        let mut f = try!(File::create(self.path(tileset, xtile, ytile, zoom)));
        write(&mut f)
    }
}

#[test]
fn test_file() {
    use std::env;

    let mut dir = env::temp_dir();
    dir.push("t_rex_test");
    let basepath = format!("{}", &dir.display());
    fs::remove_dir_all(&basepath);

    let cache = Filecache { basepath: basepath };
    assert_eq!(cache.dir("tileset", 1, 2, 0), format!("{}/{}", cache.basepath, "0/1"));
    let pbf = format!("{}/{}", cache.basepath, "0/1/2.pbf");
    assert_eq!(cache.path("tileset", 1, 2, 0), pbf);

    // Cache miss
    assert!(cache.lookup("tileset", 1, 2, 0, |_| Ok(())).is_err());

    // Write into cache
    let res = cache.store("tileset", 1, 2, 0, |f| {
        f.write_all("0123456789".as_bytes())
    });
    assert_eq!(res.ok(), Some(()));
    assert!(Path::new(&pbf).exists());

    // Cache hit
    assert!(cache.lookup("tileset", 1, 2, 0, |_| Ok(())).is_ok());

    // Read from cache
    let mut s = String::new();
    cache.lookup("tileset", 1, 2, 0, |f| {
        f.read_to_string(&mut s).map(|_| ())
    });
    assert_eq!(&s, "0123456789");
}
<commit_msg>use tileset name in cache path<commit_after>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use cache::cache::Cache;
use std::fs::File;
use std::fs;
use std::io::{Read,Write};
use std::io;
use std::path::Path;

pub struct Filecache {
    pub basepath: String,
}

impl Filecache {
    fn dir(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16) -> String {
        format!("{}/{}/{}/{}", self.basepath, tileset, zoom, xtile)
    }
    fn path(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16) -> String {
        format!("{}/{}.pbf", self.dir(tileset, xtile, ytile, zoom), ytile)
    }
}

impl Cache for Filecache {
    fn lookup<F>(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16, mut read: F) -> Result<(), io::Error>
        where F : FnMut(&mut Read) -> Result<(), io::Error>
    {
        match File::open(&self.path(tileset, xtile, ytile, zoom)) {
            Ok(mut f) => read(&mut f),
            Err(e) => Err(e)
        }
    }
    fn store<F>(&self, tileset: &str, xtile: u16, ytile: u16, zoom: u16, mut write: F) -> Result<(), io::Error>
        where F : Fn(&mut Write) -> Result<(), io::Error>
    {
        let dir = self.dir(tileset, xtile, ytile, zoom);
        try!(fs::create_dir_all(Path::new(&dir as &str)));
        let mut f = try!(File::create(self.path(tileset, xtile, ytile, zoom)));
        write(&mut f)
    }
}

#[test]
fn test_file() {
    use std::env;

    let mut dir = env::temp_dir();
    dir.push("t_rex_test");
    let basepath = format!("{}", &dir.display());
    fs::remove_dir_all(&basepath);

    let cache = Filecache { basepath: basepath };
    assert_eq!(cache.dir("tileset", 1, 2, 0), format!("{}/{}", cache.basepath, "tileset/0/1"));
    let pbf = format!("{}/{}", cache.basepath, "tileset/0/1/2.pbf");
    assert_eq!(cache.path("tileset", 1, 2, 0), pbf);

    // Cache miss
    assert!(cache.lookup("tileset", 1, 2, 0, |_| Ok(())).is_err());

    // Write into cache
    let res = cache.store("tileset", 1, 2, 0, |f| {
        f.write_all("0123456789".as_bytes())
    });
    assert_eq!(res.ok(), Some(()));
    assert!(Path::new(&pbf).exists());

    // Cache hit
    assert!(cache.lookup("tileset", 1, 2, 0, |_| Ok(())).is_ok());

    // Read from cache
    let mut s = String::new();
    cache.lookup("tileset", 1, 2, 0, |f| {
        f.read_to_string(&mut s).map(|_| ())
    });
    assert_eq!(&s, "0123456789");
}
<|endoftext|>


<commit_before>/* chips::sam4l::ast -- Implementation of a single hardware timer.
 *
 * Author: Amit Levy <levya@cs.stanford.edu>
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: 7/16/15
 */

use core::cell::Cell;
use core::intrinsics;
use nvic;
use hil::alarm::{Alarm, AlarmClient, Freq1Khz};
use hil::Controller;
use chip;
use pm::{self, PBDClock};

#[repr(C, packed)]
#[allow(missing_copy_implementations)]
struct AstRegisters {
    cr: u32,
    cv: u32,
    sr: u32,
    scr: u32,
    ier: u32,
    idr: u32,
    imr: u32,
    wer: u32,
    //0x20
    ar0: u32,
    ar1: u32,
    reserved0: [u32; 2],
    pir0: u32,
    pir1: u32,
    reserved1: [u32; 2],
    //0x40
    clock: u32,
    dtr: u32,
    eve: u32,
    evd: u32,
    evm: u32,
    calv: u32
    //we leave out parameter and version
}

pub const AST_BASE: isize = 0x400F0800;

#[allow(missing_copy_implementations)]
pub struct Ast {
    regs: *mut AstRegisters,
    callback: Cell<Option<&'static AlarmClient>>
}

pub static mut AST : Ast = Ast {
    regs: AST_BASE as *mut AstRegisters,
    callback: Cell::new(None)
};

impl Controller for Ast {
    type Config = &'static AlarmClient;

    fn configure(&self, client: &'static AlarmClient) {
        self.callback.set(Some(client));

        unsafe {
            pm::enable_clock(pm::Clock::PBD(PBDClock::AST));
        }
        self.select_clock(Clock::ClockOsc32);
        self.set_prescalar(4); // 32Khz / (2^(4 + 1)) = 1Khz
        self.enable_alarm_wake();
        self.clear_alarm();

        self.enable();
    }
}

#[repr(usize)]
pub enum Clock {
    ClockRCSys = 0,
    ClockOsc32 = 1,
    ClockAPB = 2,
    ClockGclk2 = 3,
    Clock1K = 4
}

impl Ast {
    pub fn clock_busy(&self) -> bool {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).sr) & (1 << 28) != 0
        }
    }

    pub fn busy(&self) -> bool {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).sr) & (1 << 24) != 0
        }
    }

    // Clears the alarm bit in the status register (indicating the alarm value
    // has been reached).
    pub fn clear_alarm(&self) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).scr, 1 << 8);
            nvic::clear_pending(nvic::NvicIdx::ASTALARM);
        }
    }

    // Clears the per0 bit in the status register (indicating the alarm value
    // has been reached).
    pub fn clear_periodic(&mut self) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).scr, 1 << 16);
        }
    }

    pub fn select_clock(&self, clock: Clock) {
        unsafe {
          // Disable clock by setting first bit to zero
          while self.clock_busy() {}
          let enb = intrinsics::volatile_load(&(*self.regs).clock) & !1;
          intrinsics::volatile_store(&mut (*self.regs).clock, enb);
          while self.clock_busy() {}

          // Select clock
          intrinsics::volatile_store(&mut (*self.regs).clock, (clock as u32) << 8);
          while self.clock_busy() {}

          // Re-enable clock
          let enb = intrinsics::volatile_load(&(*self.regs).clock) | 1;
          intrinsics::volatile_store(&mut (*self.regs).clock, enb);
        }
    }

    pub fn enable(&self) {
        while self.busy() {}
        unsafe {
            let cr = intrinsics::volatile_load(&(*self.regs).cr) | 1;
            intrinsics::volatile_store(&mut (*self.regs).cr, cr);
        }
    }

    pub fn disable(&self) {
        while self.busy() {}
        unsafe {
            let cr = intrinsics::volatile_load(&(*self.regs).cr) & !1;
            intrinsics::volatile_store(&mut (*self.regs).cr, cr);
        }
    }

    pub fn set_prescalar(&self, val: u8) {
        while self.busy() {}
        unsafe {
            let cr = intrinsics::volatile_load(&(*self.regs).cr) | (val as u32) << 16;
            intrinsics::volatile_store(&mut (*self.regs).cr, cr);
        }
    }

    pub fn enable_alarm_irq(&self) {
        unsafe {
            nvic::enable(nvic::NvicIdx::ASTALARM);
            intrinsics::volatile_store(&mut (*self.regs).ier, 1 << 8);
        }
    }

    pub fn disable_alarm_irq(&self) {
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).idr, 1 << 8);
        }
    }

    pub fn enable_ovf_irq(&mut self) {
        unsafe {
            nvic::enable(nvic::NvicIdx::ASTOVF);
            intrinsics::volatile_store(&mut (*self.regs).ier, 1);
        }
    }

    pub fn disable_ovf_irq(&mut self) {
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).idr, 1);
        }
    }

    pub fn enable_periodic_irq(&mut self) {
        unsafe {
            nvic::enable(nvic::NvicIdx::ASTPER);
            intrinsics::volatile_store(&mut (*self.regs).ier, 1 << 16);
        }
    }

    pub fn disable_periodic_irq(&mut self) {
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).idr, 1 << 16);
        }
    }

    pub fn enable_alarm_wake(&self) {
        while self.busy() {}
        unsafe {
            let wer = intrinsics::volatile_load(&mut (*self.regs).wer) | 1 << 8;
            intrinsics::volatile_store(&mut (*self.regs).wer, wer);
        }
    }

    pub fn set_periodic_interval(&mut self, interval: u32) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).pir0, interval);
        }
    }

    pub fn get_counter(&self) -> u32 {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_load(&(*self.regs).cv)
        }
    }

    pub fn set_counter(&self, value: u32) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).cv, value);
        }
    }

    pub fn handle_interrupt(&mut self) {
        self.clear_alarm();
        self.callback.get().map(|cb| {
            cb.fired();
        });
    }

}

impl Alarm for Ast {

    type Frequency = Freq1Khz;

    fn now(&self) -> u32 {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).cv)
        }
    }

    fn disable_alarm(&self) {
        self.disable_alarm_irq();
    }

    fn set_alarm(&self, tics: u32) {
        self.disable();
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).ar0, tics);
        }
        self.clear_alarm();
        self.enable_alarm_irq();
        self.enable();
    }

    fn get_alarm(&self) -> u32 {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).ar0)
        }
    }
}

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

    nvic::disable(nvic::NvicIdx::ASTALARM);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::ASTALARM);
}

<commit_msg>SAM4L: Use 16Khz AST instead of prescaling down to 1Khz<commit_after>/* chips::sam4l::ast -- Implementation of a single hardware timer.
 *
 * Author: Amit Levy <levya@cs.stanford.edu>
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: 7/16/15
 */

use core::cell::Cell;
use core::intrinsics;
use nvic;
use hil::alarm::{Alarm, AlarmClient, Freq16Khz};
use hil::Controller;
use chip;
use pm::{self, PBDClock};

#[repr(C, packed)]
#[allow(missing_copy_implementations)]
struct AstRegisters {
    cr: u32,
    cv: u32,
    sr: u32,
    scr: u32,
    ier: u32,
    idr: u32,
    imr: u32,
    wer: u32,
    //0x20
    ar0: u32,
    ar1: u32,
    reserved0: [u32; 2],
    pir0: u32,
    pir1: u32,
    reserved1: [u32; 2],
    //0x40
    clock: u32,
    dtr: u32,
    eve: u32,
    evd: u32,
    evm: u32,
    calv: u32
    //we leave out parameter and version
}

pub const AST_BASE: isize = 0x400F0800;

#[allow(missing_copy_implementations)]
pub struct Ast {
    regs: *mut AstRegisters,
    callback: Cell<Option<&'static AlarmClient>>
}

pub static mut AST : Ast = Ast {
    regs: AST_BASE as *mut AstRegisters,
    callback: Cell::new(None)
};

impl Controller for Ast {
    type Config = &'static AlarmClient;

    fn configure(&self, client: &'static AlarmClient) {
        self.callback.set(Some(client));

        unsafe {
            pm::enable_clock(pm::Clock::PBD(PBDClock::AST));
        }
        self.select_clock(Clock::ClockOsc32);
        self.set_prescalar(0); // 32Khz / (2^(0 + 1)) = 16Khz
        self.enable_alarm_wake();
        self.clear_alarm();

        self.enable();
    }
}

#[repr(usize)]
pub enum Clock {
    ClockRCSys = 0,
    ClockOsc32 = 1,
    ClockAPB = 2,
    ClockGclk2 = 3,
    Clock1K = 4
}

impl Ast {
    pub fn clock_busy(&self) -> bool {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).sr) & (1 << 28) != 0
        }
    }

    pub fn busy(&self) -> bool {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).sr) & (1 << 24) != 0
        }
    }

    // Clears the alarm bit in the status register (indicating the alarm value
    // has been reached).
    pub fn clear_alarm(&self) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).scr, 1 << 8);
            nvic::clear_pending(nvic::NvicIdx::ASTALARM);
        }
    }

    // Clears the per0 bit in the status register (indicating the alarm value
    // has been reached).
    pub fn clear_periodic(&mut self) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).scr, 1 << 16);
        }
    }

    pub fn select_clock(&self, clock: Clock) {
        unsafe {
          // Disable clock by setting first bit to zero
          while self.clock_busy() {}
          let enb = intrinsics::volatile_load(&(*self.regs).clock) & !1;
          intrinsics::volatile_store(&mut (*self.regs).clock, enb);
          while self.clock_busy() {}

          // Select clock
          intrinsics::volatile_store(&mut (*self.regs).clock, (clock as u32) << 8);
          while self.clock_busy() {}

          // Re-enable clock
          let enb = intrinsics::volatile_load(&(*self.regs).clock) | 1;
          intrinsics::volatile_store(&mut (*self.regs).clock, enb);
        }
    }

    pub fn enable(&self) {
        while self.busy() {}
        unsafe {
            let cr = intrinsics::volatile_load(&(*self.regs).cr) | 1;
            intrinsics::volatile_store(&mut (*self.regs).cr, cr);
        }
    }

    pub fn disable(&self) {
        while self.busy() {}
        unsafe {
            let cr = intrinsics::volatile_load(&(*self.regs).cr) & !1;
            intrinsics::volatile_store(&mut (*self.regs).cr, cr);
        }
    }

    pub fn set_prescalar(&self, val: u8) {
        while self.busy() {}
        unsafe {
            let cr = intrinsics::volatile_load(&(*self.regs).cr) | (val as u32) << 16;
            intrinsics::volatile_store(&mut (*self.regs).cr, cr);
        }
    }

    pub fn enable_alarm_irq(&self) {
        unsafe {
            nvic::enable(nvic::NvicIdx::ASTALARM);
            intrinsics::volatile_store(&mut (*self.regs).ier, 1 << 8);
        }
    }

    pub fn disable_alarm_irq(&self) {
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).idr, 1 << 8);
        }
    }

    pub fn enable_ovf_irq(&mut self) {
        unsafe {
            nvic::enable(nvic::NvicIdx::ASTOVF);
            intrinsics::volatile_store(&mut (*self.regs).ier, 1);
        }
    }

    pub fn disable_ovf_irq(&mut self) {
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).idr, 1);
        }
    }

    pub fn enable_periodic_irq(&mut self) {
        unsafe {
            nvic::enable(nvic::NvicIdx::ASTPER);
            intrinsics::volatile_store(&mut (*self.regs).ier, 1 << 16);
        }
    }

    pub fn disable_periodic_irq(&mut self) {
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).idr, 1 << 16);
        }
    }

    pub fn enable_alarm_wake(&self) {
        while self.busy() {}
        unsafe {
            let wer = intrinsics::volatile_load(&mut (*self.regs).wer) | 1 << 8;
            intrinsics::volatile_store(&mut (*self.regs).wer, wer);
        }
    }

    pub fn set_periodic_interval(&mut self, interval: u32) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).pir0, interval);
        }
    }

    pub fn get_counter(&self) -> u32 {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_load(&(*self.regs).cv)
        }
    }

    pub fn set_counter(&self, value: u32) {
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).cv, value);
        }
    }

    pub fn handle_interrupt(&mut self) {
        self.clear_alarm();
        self.callback.get().map(|cb| {
            cb.fired();
        });
    }

}

impl Alarm for Ast {

    type Frequency = Freq16Khz;

    fn now(&self) -> u32 {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).cv)
        }
    }

    fn disable_alarm(&self) {
        self.disable_alarm_irq();
    }

    fn set_alarm(&self, tics: u32) {
        self.disable();
        while self.busy() {}
        unsafe {
            intrinsics::volatile_store(&mut (*self.regs).ar0, tics);
        }
        self.clear_alarm();
        self.enable_alarm_irq();
        self.enable();
    }

    fn get_alarm(&self) -> u32 {
        unsafe {
            intrinsics::volatile_load(&(*self.regs).ar0)
        }
    }
}

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

    nvic::disable(nvic::NvicIdx::ASTALARM);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::ASTALARM);
}

<|endoftext|>


<commit_before>use std::io;

use super::{Numeric, SignedNumeric, BitQueueBE, BitQueueLE, BitQueue};

/// For reading bit values from an underlying stream
/// in a given endianness.
pub trait BitRead {
    /// Reads an unsigned value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read<U>(&mut self, bits: u32) -> Result<U, io::Error>
        where U: Numeric;

    /// Reads a twos-complement signed value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric;

    /// Skips the given number of bits in the stream.
    /// Since this method does not need an accumulator,
    /// it may be slightly faster than reading to an empty variable.
    fn skip(&mut self, bits: u32) -> Result<(), io::Error>;

    /// Completely fills the given buffer with whole bytes.
    /// If the stream is already byte-aligned, it will map
    /// to a faster `read_exact` call.  Otherwise it will read
    /// bytes individually in 8-bit increments.
    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error>;

    /// Reads an unsigned unary value with a stop bit of 0.
    fn read_unary0(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 0 {
            acc += 1;
        }
        Ok(acc)
    }

    /// Reads an unsigned unary value with a stop bit of 1.
    fn read_unary1(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 1 {
            acc += 1;
        }
        Ok(acc)
    }

    /// Returns true if the stream is aligned at a whole byte.
    fn byte_aligned(&self) -> bool;

    /// Throws away all unread bit values until the next whole byte.
    fn byte_align(&mut self);

    /*FIXME - add support for reading Huffman codes*/
}

/// A wrapper for reading values from a big-endian stream.
pub struct BitReaderBE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueBE<u8>
}

impl<'a> BitReaderBE<'a> {
    /// Wraps a big-endian reader around a `BufRead` reference.
    ///
    /// A `BufRead` is required because this reader is liable
    /// to make many small reads to the stream in normal operation,
    /// so reading from the buffer directly is preferable
    /// to making many calls to `read_exact`.
    pub fn new(reader: &mut io::BufRead) -> BitReaderBE {
        BitReaderBE{reader: reader, bitqueue: BitQueueBE::new()}
    }
}

impl<'a> BitRead for BitReaderBE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;
        let mut acc: BitQueueBE<U> = BitQueueBE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let sign = self.read::<S>(1)?;
        let unsigned = self.read::<S>(bits - 1)?;
        Ok(if sign.is_zero() {unsigned} else{unsigned.as_negative(bits)})
    }

    fn skip(&mut self, bits: u32) -> Result<(), io::Error> {
        /*FIXME - optimize this*/
        self.read::<u32>(bits).map(|_| ())
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

/// A wrapper for reading values from a little-endian stream.
pub struct BitReaderLE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueLE<u8>
}

impl<'a> BitReaderLE<'a> {
    /// Wraps a little-endian reader around a `BufRead` reference.
    ///
    /// A `BufRead` is required because this reader is liable
    /// to make many small reads to the stream in normal operation,
    /// so reading from the buffer directly is preferable
    /// to making many calls to `read_exact`.
    pub fn new(reader: &mut io::BufRead) -> BitReaderLE {
        BitReaderLE{reader: reader, bitqueue: BitQueueLE::new()}
    }
}

impl<'a> BitRead for BitReaderLE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;

        let mut acc: BitQueueLE<U> = BitQueueLE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let unsigned = self.read::<S>(bits - 1)?;
        let sign = self.read::<S>(1)?;
        Ok(if sign.is_zero() {unsigned} else {unsigned.as_negative(bits)})
    }

    fn skip(&mut self, bits: u32) -> Result<(), io::Error> {
        /*FIXME - optimize this*/
        self.read::<u32>(bits).map(|_| ())
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

fn read_aligned<N>(reader: &mut io::BufRead,
                   mut bytes: u32,
                   acc: &mut BitQueue<N>) -> Result<(), io::Error>
    where N: Numeric {
    use std::cmp::min;

    while bytes > 0 {
        let processed = {
            let buf = reader.fill_buf()?;
            let to_process = min(bytes as usize, buf.len());
            for b in &buf[0..to_process] {
                acc.push(8, N::from_u8(*b));
            }
            to_process
        };
        if processed > 0 {
            reader.consume(processed);
            bytes -= processed as u32;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"));
        }
    }
    Ok(())
}

fn read_unaligned<N>(reader: &mut io::BufRead,
                     bits: u32,
                     acc: &mut BitQueue<N>,
                     rem: &mut BitQueue<u8>) -> Result<(), io::Error>
    where N: Numeric {

    debug_assert!(bits <= 8);

    if bits > 0 {
        let length = {
            let buf = reader.fill_buf()?;
            if buf.len() > 0 {
                rem.set(buf[0], 8);
                acc.push(bits, N::from_u8(rem.pop(bits)));
                1
            } else {0}
        };
        if length > 0 {
            Ok(reader.consume(length))
        } else {
            Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"))
        }
    } else {
        Ok(())
    }
}
<commit_msg>Add better performance to skip() methods<commit_after>use std::io;

use super::{Numeric, SignedNumeric, BitQueueBE, BitQueueLE, BitQueue};

/// For reading bit values from an underlying stream
/// in a given endianness.
pub trait BitRead {
    /// Reads an unsigned value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read<U>(&mut self, bits: u32) -> Result<U, io::Error>
        where U: Numeric;

    /// Reads a twos-complement signed value from the stream with
    /// the given number of bits.  This method assumes
    /// that the programmer is using an output type
    /// sufficiently large to hold those bits.
    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric;

    /// Skips the given number of bits in the stream.
    /// Since this method does not need an accumulator,
    /// it may be slightly faster than reading to an empty variable.
    /// In addition, since there is no accumulator,
    /// there is no upper limit on the number of bytes
    /// which may be skipped.
    /// These bytes are still read from the stream, however,
    /// and are never skipped via a `seek` method.
    fn skip(&mut self, bits: u32) -> Result<(), io::Error>;

    /// Completely fills the given buffer with whole bytes.
    /// If the stream is already byte-aligned, it will map
    /// to a faster `read_exact` call.  Otherwise it will read
    /// bytes individually in 8-bit increments.
    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error>;

    /// Reads an unsigned unary value with a stop bit of 0.
    fn read_unary0(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 0 {
            acc += 1;
        }
        Ok(acc)
    }

    /// Reads an unsigned unary value with a stop bit of 1.
    fn read_unary1(&mut self) -> Result<u32, io::Error> {
        /*FIXME - optimize this*/
        let mut acc = 0;
        while self.read::<u32>(1)? != 1 {
            acc += 1;
        }
        Ok(acc)
    }

    /// Returns true if the stream is aligned at a whole byte.
    fn byte_aligned(&self) -> bool;

    /// Throws away all unread bit values until the next whole byte.
    fn byte_align(&mut self);

    /*FIXME - add support for reading Huffman codes*/
}

/// A wrapper for reading values from a big-endian stream.
pub struct BitReaderBE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueBE<u8>
}

impl<'a> BitReaderBE<'a> {
    /// Wraps a big-endian reader around a `BufRead` reference.
    ///
    /// A `BufRead` is required because this reader is liable
    /// to make many small reads to the stream in normal operation,
    /// so reading from the buffer directly is preferable
    /// to making many calls to `read_exact`.
    pub fn new(reader: &mut io::BufRead) -> BitReaderBE {
        BitReaderBE{reader: reader, bitqueue: BitQueueBE::new()}
    }
}

impl<'a> BitRead for BitReaderBE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;
        let mut acc: BitQueueBE<U> = BitQueueBE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn skip(&mut self, mut bits: u32) -> Result<(), io::Error> {
        use std::cmp::min;

        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_drop = min(queue_len, bits);
            self.bitqueue.pop(to_drop);
            bits -= to_drop;
        }

        skip_aligned(&mut self.reader, bits / 8)
        .and_then(|()| skip_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut self.bitqueue))
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let sign = self.read::<S>(1)?;
        let unsigned = self.read::<S>(bits - 1)?;
        Ok(if sign.is_zero() {unsigned} else{unsigned.as_negative(bits)})
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

/// A wrapper for reading values from a little-endian stream.
pub struct BitReaderLE<'a> {
    reader: &'a mut io::BufRead,
    bitqueue: BitQueueLE<u8>
}

impl<'a> BitReaderLE<'a> {
    /// Wraps a little-endian reader around a `BufRead` reference.
    ///
    /// A `BufRead` is required because this reader is liable
    /// to make many small reads to the stream in normal operation,
    /// so reading from the buffer directly is preferable
    /// to making many calls to `read_exact`.
    pub fn new(reader: &mut io::BufRead) -> BitReaderLE {
        BitReaderLE{reader: reader, bitqueue: BitQueueLE::new()}
    }
}

impl<'a> BitRead for BitReaderLE<'a> {
    fn read<U>(&mut self, mut bits: u32) -> Result<U, io::Error>
        where U: Numeric {
        use std::cmp::min;

        let mut acc: BitQueueLE<U> = BitQueueLE::new();

        /*transfer un-processed bits from queue to accumulator*/
        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_transfer = min(queue_len, bits);
            acc.push(to_transfer, U::from_u8(self.bitqueue.pop(to_transfer)));
            bits -= to_transfer;
        }

        read_aligned(&mut self.reader, bits / 8, &mut acc)
        .and_then(|()| read_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut acc,
                                      &mut self.bitqueue))
        .map(|()| acc.value())
    }

    fn skip(&mut self, mut bits: u32) -> Result<(), io::Error> {
        use std::cmp::min;

        let queue_len = self.bitqueue.len();
        if queue_len > 0 {
            let to_drop = min(queue_len, bits);
            self.bitqueue.pop(to_drop);
            bits -= to_drop;
        }

        skip_aligned(&mut self.reader, bits / 8)
        .and_then(|()| skip_unaligned(&mut self.reader,
                                      bits % 8,
                                      &mut self.bitqueue))
    }

    fn read_signed<S>(&mut self, bits: u32) -> Result<S, io::Error>
        where S: SignedNumeric {
        debug_assert!(bits >= 1);
        let unsigned = self.read::<S>(bits - 1)?;
        let sign = self.read::<S>(1)?;
        Ok(if sign.is_zero() {unsigned} else {unsigned.as_negative(bits)})
    }

    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), io::Error> {
        if self.byte_aligned() {
            self.reader.read_exact(buf)
        } else {
            for b in buf.iter_mut() {
                *b = self.read::<u8>(8)?;
            }
            Ok(())
        }
    }

    #[inline]
    fn byte_aligned(&self) -> bool {
        self.bitqueue.is_empty()
    }

    #[inline]
    fn byte_align(&mut self) {
        self.bitqueue.clear()
    }
}

fn read_aligned<N>(reader: &mut io::BufRead,
                   mut bytes: u32,
                   acc: &mut BitQueue<N>) -> Result<(), io::Error>
    where N: Numeric {
    use std::cmp::min;

    while bytes > 0 {
        let processed = {
            let buf = reader.fill_buf()?;
            let to_process = min(bytes as usize, buf.len());
            for b in &buf[0..to_process] {
                acc.push(8, N::from_u8(*b));
            }
            to_process
        };
        if processed > 0 {
            reader.consume(processed);
            bytes -= processed as u32;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"));
        }
    }
    Ok(())
}

fn read_unaligned<N>(reader: &mut io::BufRead,
                     bits: u32,
                     acc: &mut BitQueue<N>,
                     rem: &mut BitQueue<u8>) -> Result<(), io::Error>
    where N: Numeric {

    debug_assert!(bits <= 8);

    if bits > 0 {
        let length = {
            let buf = reader.fill_buf()?;
            if buf.len() > 0 {
                rem.set(buf[0], 8);
                acc.push(bits, N::from_u8(rem.pop(bits)));
                1
            } else {0}
        };
        if length > 0 {
            Ok(reader.consume(length))
        } else {
            Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"))
        }
    } else {
        Ok(())
    }
}

fn skip_aligned(reader: &mut io::BufRead,
                mut bytes: u32) -> Result<(), io::Error> {
    use std::cmp::min;

    while bytes > 0 {
        let processed = {
            let buf = reader.fill_buf()?;
            let to_process = min(bytes as usize, buf.len());
            to_process
        };
        if processed > 0 {
            reader.consume(processed);
            bytes -= processed as u32;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"));
        }
    }
    Ok(())
}

fn skip_unaligned(reader: &mut io::BufRead,
                  bits: u32,
                  rem: &mut BitQueue<u8>) -> Result<(), io::Error> {
    debug_assert!(bits <= 8);

    if bits > 0 {
        let length = {
            let buf = reader.fill_buf()?;
            if buf.len() > 0 {
                rem.set(buf[0], 8);
                rem.pop(bits);
                1
            } else {0}
        };
        if length > 0 {
            Ok(reader.consume(length))
        } else {
            Err(io::Error::new(
                io::ErrorKind::UnexpectedEof, "EOF in stream"))
        }
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! A lightweight serde deserializer for strings containing key-value pairs separated by commas, as
//! commonly found in command-line parameters.
//!
//! Say your program takes a command-line option of the form:
//!
//! ```text
//! --foo type=bar,active,nb_threads=8
//! ```
//!
//! This crate provides a [from_key_values] function that deserializes these key-values into a
//! configuration structure. Since it uses serde, the same configuration structure can also be
//! created from any other supported source (such as a TOML or YAML configuration file) that uses
//! the same keys.
//!
//! Integration with the [argh](https://github.com/google/argh) command-line parser is also
//! provided via the `argh_derive` feature.
//!
//! The deserializer supports parsing signed and unsigned integers, booleans, strings (quoted or
//! not), paths, and enums inside a top-level struct. The order in which the fields appear in the
//! string is not important.
//!
//! Simple example:
//!
//! ```
//! use serde_keyvalue::from_key_values;
//! use serde::Deserialize;
//!
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("path=/some/path,threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 16, active: true });
//!
//! let config: Config = from_key_values("threads=16,active=true,path=/some/path").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 16, active: true });
//! ```
//!
//! As a convenience the name of the first field of a struct can be omitted:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("/some/path,threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 16, active: true });
//! ```
//!
//! Fields that are behind an `Option` can be omitted, in which case they will be `None`.
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: Option<String>,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("path=/some/path,threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: Some("/some/path".into()), threads: 16, active: true });
//!
//! let config: Config = from_key_values("threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: None, threads: 16, active: true });
//! ```
//!
//! Alternatively, the serde `default` attribute can be used on select fields or on the whole
//! struct to make unspecified fields be assigned their default value. In the following example only
//! the `path` parameter must be specified.
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     #[serde(default)]
//!     threads: u8,
//!     #[serde(default)]
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("path=/some/path").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 0, active: false });
//! ```
//!
//! A function providing a default value can also be specified, see the [serde documentation for
//! field attributes](https://serde.rs/field-attrs.html) for details.
//!
//! Booleans can be `true` or `false`, or take no value at all, in which case they will be `true`.
//! Combined with default values this allows to implement flags very easily:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, Default, PartialEq, Deserialize)]
//! #[serde(default)]
//! struct Config {
//!     active: bool,
//!     delayed: bool,
//!     pooled: bool,
//! }
//!
//! let config: Config = from_key_values("active=true,delayed=false,pooled=true").unwrap();
//! assert_eq!(config, Config { active: true, delayed: false, pooled: true });
//!
//! let config: Config = from_key_values("active,pooled").unwrap();
//! assert_eq!(config, Config { active: true, delayed: false, pooled: true });
//! ```
//!
//! Strings can be quoted, which is useful if they e.g. need to include a comma. Quoted strings can
//! also contain escaped characters, where any character after a `\` is repeated as-is:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//! }
//!
//! let config: Config = from_key_values(r#"path="/some/\"strange\"/pa,th""#).unwrap();
//! assert_eq!(config, Config { path: r#"/some/"strange"/pa,th"#.into() });
//! ```
//!
//! Enums can be directly specified by name. It is recommended to use the `rename_all` serde
//! container attribute to make them parseable using snake or kebab case representation. Serde's
//! `rename` and `alias` field attributes can also be used to provide shorter values:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! #[serde(rename_all="kebab-case")]
//! enum Mode {
//!     Slow,
//!     Fast,
//!     #[serde(rename="ludicrous")]
//!     LudicrousSpeed,
//! }
//!
//! #[derive(Deserialize, PartialEq, Debug)]
//! struct Config {
//!     mode: Mode,
//! }
//!
//! let config: Config = from_key_values("mode=slow").unwrap();
//! assert_eq!(config, Config { mode: Mode::Slow });
//!
//! let config: Config = from_key_values("mode=ludicrous").unwrap();
//! assert_eq!(config, Config { mode: Mode::LudicrousSpeed });
//! ```
//!
//! Enums taking a single value should use the `flatten` field attribute in order to be inferred
//! from their variant key directly:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! #[serde(rename_all="kebab-case")]
//! enum Mode {
//!     // Work with a local file.
//!     File(String),
//!     // Work with a remote URL.
//!     Url(String),
//! }
//!
//! #[derive(Deserialize, PartialEq, Debug)]
//! struct Config {
//!     #[serde(flatten)]
//!     mode: Mode,
//! }
//!
//! let config: Config = from_key_values("file=/some/path").unwrap();
//! assert_eq!(config, Config { mode: Mode::File("/some/path".into()) });
//!
//! let config: Config = from_key_values("url=https://www.google.com").unwrap();
//! assert_eq!(config, Config { mode: Mode::Url("https://www.google.com".into()) });
//! ```
//!
//! The `flatten` attribute can also be used to embed one struct within another one and parse both
//! from the same string:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct BaseConfig {
//!     enabled: bool,
//!     num_threads: u8,
//! }
//!
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     #[serde(flatten)]
//!     base: BaseConfig,
//!     path: String,
//! }
//!
//! let config: Config = from_key_values("path=/some/path,enabled,num_threads=16").unwrap();
//! assert_eq!(
//!     config,
//!     Config {
//!         path: "/some/path".into(),
//!         base: BaseConfig {
//!             num_threads: 16,
//!             enabled: true,
//!         }
//!     }
//! );
//! ```
//!
//! If an enum's variants are made of structs, it should take the `untagged` container attribute so
//! it can be inferred directly from the fields of the embedded structs:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! #[serde(untagged)]
//! enum Mode {
//!     // Work with a local file.
//!     File {
//!         path: String,
//!         #[serde(default)]
//!         read_only: bool,
//!     },
//!     // Work with a remote URL.
//!     Remote {
//!         server: String,
//!         port: u16,
//!     }
//! }
//!
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     #[serde(flatten)]
//!     mode: Mode,
//! }
//!
//! let config: Config = from_key_values("path=/some/path").unwrap();
//! assert_eq!(config, Config { mode: Mode::File { path: "/some/path".into(), read_only: false } });
//!
//! let config: Config = from_key_values("server=google.com,port=80").unwrap();
//! assert_eq!(config, Config { mode: Mode::Remote { server: "google.com".into(), port: 80 } });
//! ```
//!
//! Using this crate, parsing errors and invalid or missing fields are precisely reported:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config = from_key_values::<Config>("path=/some/path,active=true").unwrap_err();
//! assert_eq!(format!("{}", config), "missing field `threads`");
//! ```
//!
//! Most of the serde [container](https://serde.rs/container-attrs.html) and
//! [field](https://serde.rs/field-attrs.html) attributes can be applied to your configuration
//! struct. Most useful ones include
//! [`deny_unknown_fields`](https://serde.rs/container-attrs.html#deny_unknown_fields) to report an
//! error if an unknown field is met in the input, and
//! [`deserialize_with`](https://serde.rs/field-attrs.html#deserialize_with) to use a custom
//! deserialization function for a specific field.
#![deny(missing_docs)]

mod key_values;

#[cfg(feature = "argh_derive")]
pub use argh;
pub use key_values::from_key_values;
pub use key_values::ErrorKind;
pub use key_values::KeyValueDeserializer;
pub use key_values::ParseError;
#[cfg(feature = "argh_derive")]
pub use serde_keyvalue_derive::FromKeyValues;
<commit_msg>serde_keyvalue: add documentation about caveats of using `flatten`<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! A lightweight serde deserializer for strings containing key-value pairs separated by commas, as
//! commonly found in command-line parameters.
//!
//! Say your program takes a command-line option of the form:
//!
//! ```text
//! --foo type=bar,active,nb_threads=8
//! ```
//!
//! This crate provides a [from_key_values] function that deserializes these key-values into a
//! configuration structure. Since it uses serde, the same configuration structure can also be
//! created from any other supported source (such as a TOML or YAML configuration file) that uses
//! the same keys.
//!
//! Integration with the [argh](https://github.com/google/argh) command-line parser is also
//! provided via the `argh_derive` feature.
//!
//! The deserializer supports parsing signed and unsigned integers, booleans, strings (quoted or
//! not), paths, and enums inside a top-level struct. The order in which the fields appear in the
//! string is not important.
//!
//! Simple example:
//!
//! ```
//! use serde_keyvalue::from_key_values;
//! use serde::Deserialize;
//!
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("path=/some/path,threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 16, active: true });
//!
//! let config: Config = from_key_values("threads=16,active=true,path=/some/path").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 16, active: true });
//! ```
//!
//! As a convenience the name of the first field of a struct can be omitted:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("/some/path,threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 16, active: true });
//! ```
//!
//! Fields that are behind an `Option` can be omitted, in which case they will be `None`.
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: Option<String>,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("path=/some/path,threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: Some("/some/path".into()), threads: 16, active: true });
//!
//! let config: Config = from_key_values("threads=16,active=true").unwrap();
//! assert_eq!(config, Config { path: None, threads: 16, active: true });
//! ```
//!
//! Alternatively, the serde `default` attribute can be used on select fields or on the whole
//! struct to make unspecified fields be assigned their default value. In the following example only
//! the `path` parameter must be specified.
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     #[serde(default)]
//!     threads: u8,
//!     #[serde(default)]
//!     active: bool,
//! }
//!
//! let config: Config = from_key_values("path=/some/path").unwrap();
//! assert_eq!(config, Config { path: "/some/path".into(), threads: 0, active: false });
//! ```
//!
//! A function providing a default value can also be specified, see the [serde documentation for
//! field attributes](https://serde.rs/field-attrs.html) for details.
//!
//! Booleans can be `true` or `false`, or take no value at all, in which case they will be `true`.
//! Combined with default values this allows to implement flags very easily:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, Default, PartialEq, Deserialize)]
//! #[serde(default)]
//! struct Config {
//!     active: bool,
//!     delayed: bool,
//!     pooled: bool,
//! }
//!
//! let config: Config = from_key_values("active=true,delayed=false,pooled=true").unwrap();
//! assert_eq!(config, Config { active: true, delayed: false, pooled: true });
//!
//! let config: Config = from_key_values("active,pooled").unwrap();
//! assert_eq!(config, Config { active: true, delayed: false, pooled: true });
//! ```
//!
//! Strings can be quoted, which is useful if they e.g. need to include a comma. Quoted strings can
//! also contain escaped characters, where any character after a `\` is repeated as-is:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//! }
//!
//! let config: Config = from_key_values(r#"path="/some/\"strange\"/pa,th""#).unwrap();
//! assert_eq!(config, Config { path: r#"/some/"strange"/pa,th"#.into() });
//! ```
//!
//! Enums can be directly specified by name. It is recommended to use the `rename_all` serde
//! container attribute to make them parseable using snake or kebab case representation. Serde's
//! `rename` and `alias` field attributes can also be used to provide shorter values:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! #[serde(rename_all="kebab-case")]
//! enum Mode {
//!     Slow,
//!     Fast,
//!     #[serde(rename="ludicrous")]
//!     LudicrousSpeed,
//! }
//!
//! #[derive(Deserialize, PartialEq, Debug)]
//! struct Config {
//!     mode: Mode,
//! }
//!
//! let config: Config = from_key_values("mode=slow").unwrap();
//! assert_eq!(config, Config { mode: Mode::Slow });
//!
//! let config: Config = from_key_values("mode=ludicrous").unwrap();
//! assert_eq!(config, Config { mode: Mode::LudicrousSpeed });
//! ```
//!
//! Enums taking a single value should use the `flatten` field attribute in order to be inferred
//! from their variant key directly:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! #[serde(rename_all="kebab-case")]
//! enum Mode {
//!     // Work with a local file.
//!     File(String),
//!     // Work with a remote URL.
//!     Url(String),
//! }
//!
//! #[derive(Deserialize, PartialEq, Debug)]
//! struct Config {
//!     #[serde(flatten)]
//!     mode: Mode,
//! }
//!
//! let config: Config = from_key_values("file=/some/path").unwrap();
//! assert_eq!(config, Config { mode: Mode::File("/some/path".into()) });
//!
//! let config: Config = from_key_values("url=https://www.google.com").unwrap();
//! assert_eq!(config, Config { mode: Mode::Url("https://www.google.com".into()) });
//! ```
//!
//! The `flatten` attribute can also be used to embed one struct within another one and parse both
//! from the same string:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct BaseConfig {
//!     enabled: bool,
//!     num_threads: u8,
//! }
//!
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     #[serde(flatten)]
//!     base: BaseConfig,
//!     path: String,
//! }
//!
//! let config: Config = from_key_values("path=/some/path,enabled,num_threads=16").unwrap();
//! assert_eq!(
//!     config,
//!     Config {
//!         path: "/some/path".into(),
//!         base: BaseConfig {
//!             num_threads: 16,
//!             enabled: true,
//!         }
//!     }
//! );
//! ```
//!
//! If an enum's variants are made of structs, it should take the `untagged` container attribute so
//! it can be inferred directly from the fields of the embedded structs:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! #[serde(untagged)]
//! enum Mode {
//!     // Work with a local file.
//!     File {
//!         path: String,
//!         #[serde(default)]
//!         read_only: bool,
//!     },
//!     // Work with a remote URL.
//!     Remote {
//!         server: String,
//!         port: u16,
//!     }
//! }
//!
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     #[serde(flatten)]
//!     mode: Mode,
//! }
//!
//! let config: Config = from_key_values("path=/some/path").unwrap();
//! assert_eq!(config, Config { mode: Mode::File { path: "/some/path".into(), read_only: false } });
//!
//! let config: Config = from_key_values("server=google.com,port=80").unwrap();
//! assert_eq!(config, Config { mode: Mode::Remote { server: "google.com".into(), port: 80 } });
//! ```
//!
//! Using this crate, parsing errors and invalid or missing fields are precisely reported:
//!
//! ```
//! # use serde_keyvalue::from_key_values;
//! # use serde::Deserialize;
//! #[derive(Debug, PartialEq, Deserialize)]
//! struct Config {
//!     path: String,
//!     threads: u8,
//!     active: bool,
//! }
//!
//! let config = from_key_values::<Config>("path=/some/path,active=true").unwrap_err();
//! assert_eq!(format!("{}", config), "missing field `threads`");
//! ```
//!
//! Most of the serde [container](https://serde.rs/container-attrs.html) and
//! [field](https://serde.rs/field-attrs.html) attributes can be applied to your configuration
//! struct. Most useful ones include
//! [`deny_unknown_fields`](https://serde.rs/container-attrs.html#deny_unknown_fields) to report an
//! error if an unknown field is met in the input, and
//! [`deserialize_with`](https://serde.rs/field-attrs.html#deserialize_with) to use a custom
//! deserialization function for a specific field.
//!
//! Be aware that the use of `flatten` comes with some severe limitations. Because type information
//! is not available to the deserializer, it will try to determine the type of fields using the
//! input as its sole hint. For instance, any number will be returned as an integer type, and if the
//! parsed structure was actually expecting a number as a string, then an error will occur.
//!
//! For this reason it is discouraged to use `flatten` except when neither the embedding not the
//! flattened structs has a member of string type.
//!
//! Most of the time, similar functionality can be obtained by implementing a custom deserializer
//! that parses the embedding struct's member and then the flattened struct in a specific order
//! using the [`serde_keyvalue::key_values::KeyValueDeserializer`] interface directly.
//!
//! Another limitation of using `flatten` that is inherent to serde is that it won't allow
//! `deny_unknown_fields` to be used in either the embedding or the flattened struct.
#![deny(missing_docs)]

mod key_values;

#[cfg(feature = "argh_derive")]
pub use argh;
pub use key_values::from_key_values;
pub use key_values::ErrorKind;
pub use key_values::KeyValueDeserializer;
pub use key_values::ParseError;
#[cfg(feature = "argh_derive")]
pub use serde_keyvalue_derive::FromKeyValues;
<|endoftext|>


<commit_before>//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use std::cell::Ref;

use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir;
use rustc::ty::layout::Layout;
use rustc::ty::{subst, self};

use error::{EvalResult, EvalError};
use eval_context::{EvalContext, StackPopCleanup, MirRef};
use lvalue::{Global, GlobalId, Lvalue};
use syntax::codemap::Span;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
        self.steps_remaining = self.steps_remaining.saturating_sub(n);
        if self.steps_remaining > 0 {
            Ok(())
        } else {
            Err(EvalError::ExecutionTimeLimitReached)
        }
    }

    /// Returns true as long as there are more things to do.
    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
        // see docs on the `Memory::packed` field for why we do this
        self.memory.clear_packed();
        self.inc_step_counter_and_check_limit(1)?;
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = self.frame().block;
        let stmt_id = self.frame().stmt;
        let mir = self.mir();
        let basic_block = &mir.basic_blocks()[block];

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            let mut new = Ok(0);
            ConstantExtractor {
                span: stmt.source_info.span,
                substs: self.substs(),
                def_id: self.frame().def_id,
                ecx: self,
                mir: Ref::clone(&mir),
                new_constants: &mut new,
            }.visit_statement(block, stmt, mir::Location { block, statement_index: stmt_id });
            if new? == 0 {
                self.statement(stmt)?;
            }
            // if ConstantExtractor added new frames, we don't execute anything here
            // but await the next call to step
            return Ok(true);
        }

        let terminator = basic_block.terminator();
        let mut new = Ok(0);
        ConstantExtractor {
            span: terminator.source_info.span,
            substs: self.substs(),
            def_id: self.frame().def_id,
            ecx: self,
            mir: Ref::clone(&mir),
            new_constants: &mut new,
        }.visit_terminator(block, terminator, mir::Location { block, statement_index: stmt_id });
        if new? == 0 {
            self.terminator(terminator)?;
        }
        // if ConstantExtractor added new frames, we don't execute anything here
        // but await the next call to step
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", stmt);

        use rustc::mir::StatementKind::*;
        match stmt.kind {
            Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,

            SetDiscriminant { ref lvalue, variant_index } => {
                let dest = self.eval_lvalue(lvalue)?;
                let dest_ty = self.lvalue_ty(lvalue);
                let dest_layout = self.type_layout(dest_ty)?;

                match *dest_layout {
                    Layout::General { discr, ref variants, .. } => {
                        let discr_size = discr.size().bytes();
                        let discr_offset = variants[variant_index].offsets[0].bytes();

                        // FIXME(solson)
                        let dest = self.force_allocation(dest)?;
                        let discr_dest = (dest.to_ptr()).offset(discr_offset);

                        self.memory.write_uint(discr_dest, variant_index as u128, discr_size)?;
                    }

                    Layout::RawNullablePointer { nndiscr, .. } => {
                        use value::PrimVal;
                        if variant_index as u64 != nndiscr {
                            self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
                        }
                    }

                    _ => bug!("SetDiscriminant on {} represented as {:#?}", dest_ty, dest_layout),
                }
            }

            // Miri can safely ignore these. Only translation needs it.
            StorageLive(_) |
            StorageDead(_) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}
        }

        self.frame_mut().stmt += 1;
        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", terminator.kind);
        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            trace!("// {:?}", self.frame().block);
        }
        Ok(())
    }
}

// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
// this includes any method that might access the stack
// basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
    span: Span,
    ecx: &'a mut EvalContext<'b, 'tcx>,
    mir: MirRef<'tcx>,
    def_id: DefId,
    substs: &'tcx subst::Substs<'tcx>,
    new_constants: &'a mut EvalResult<'tcx, u64>,
}

impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
    fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span, immutable: bool) {
        let (def_id, substs) = self.ecx.resolve_associated_const(def_id, substs);
        let cid = GlobalId { def_id, substs, promoted: None };
        if self.ecx.globals.contains_key(&cid) {
            return;
        }
        self.try(|this| {
            let mir = this.ecx.load_mir(def_id)?;
            this.ecx.globals.insert(cid, Global::uninitialized(mir.return_ty));
            let cleanup = StackPopCleanup::MarkStatic(!immutable || mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe());
            let name = ty::tls::with(|tcx| tcx.item_path_str(def_id));
            trace!("pushing stack frame for global: {}", name);
            this.ecx.push_stack_frame(def_id, span, mir, substs, Lvalue::Global(cid), cleanup, Vec::new())
        });
    }
    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx>>(&mut self, f: F) {
        if let Ok(ref mut n) = *self.new_constants {
            *n += 1;
        } else {
            return;
        }
        if let Err(e) = f(self) {
            *self.new_constants = Err(e);
        }
    }
}

impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
        self.super_constant(constant, location);
        match constant.literal {
            // already computed by rustc
            mir::Literal::Value { .. } => {}
            mir::Literal::Item { def_id, substs } => {
                if let ty::TyFnDef(..) = constant.ty.sty {
                    // No need to do anything here,
                    // because the type is the actual function, not the signature of the function.
                    // Thus we can simply create a zero sized allocation in `evaluate_operand`
                } else {
                    self.global_item(def_id, substs, constant.span, true);
                }
            },
            mir::Literal::Promoted { index } => {
                let cid = GlobalId {
                    def_id: self.def_id,
                    substs: self.substs,
                    promoted: Some(index),
                };
                if self.ecx.globals.contains_key(&cid) {
                    return;
                }
                let mir = Ref::clone(&self.mir);
                let mir = Ref::map(mir, |mir| &mir.promoted[index]);
                self.try(|this| {
                    let ty = this.ecx.monomorphize(mir.return_ty, this.substs);
                    this.ecx.globals.insert(cid, Global::uninitialized(ty));
                    trace!("pushing stack frame for {:?}", index);
                    this.ecx.push_stack_frame(this.def_id,
                                              constant.span,
                                              mir,
                                              this.substs,
                                              Lvalue::Global(cid),
                                              StackPopCleanup::MarkStatic(false),
                                              Vec::new())
                });
            }
        }
    }

    fn visit_lvalue(
        &mut self,
        lvalue: &mir::Lvalue<'tcx>,
        context: LvalueContext<'tcx>,
        location: mir::Location
    ) {
        self.super_lvalue(lvalue, context, location);
        if let mir::Lvalue::Static(def_id) = *lvalue {
            let substs = self.ecx.tcx.intern_substs(&[]);
            let span = self.span;
            if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) {
                if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
                    if let hir::ItemStatic(_, m, _) = *node {
                        self.global_item(def_id, substs, span, m == hir::MutImmutable);
                        return;
                    } else {
                        bug!("static def id doesn't point to static");
                    }
                } else {
                    bug!("static def id doesn't point to item");
                }
            } else {
                let def = self.ecx.tcx.sess.cstore.describe_def(def_id).expect("static not found");
                if let hir::def::Def::Static(_, mutable) = def {
                    self.global_item(def_id, substs, span, !mutable);
                } else {
                    bug!("static found but isn't a static: {:?}", def);
                }
            }
        }
    }
}
<commit_msg>Reformatting.<commit_after>//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use std::cell::Ref;

use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir;
use rustc::ty::layout::Layout;
use rustc::ty::{subst, self};

use error::{EvalResult, EvalError};
use eval_context::{EvalContext, StackPopCleanup, MirRef};
use lvalue::{Global, GlobalId, Lvalue};
use syntax::codemap::Span;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
        self.steps_remaining = self.steps_remaining.saturating_sub(n);
        if self.steps_remaining > 0 {
            Ok(())
        } else {
            Err(EvalError::ExecutionTimeLimitReached)
        }
    }

    /// Returns true as long as there are more things to do.
    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
        // see docs on the `Memory::packed` field for why we do this
        self.memory.clear_packed();
        self.inc_step_counter_and_check_limit(1)?;
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = self.frame().block;
        let stmt_id = self.frame().stmt;
        let mir = self.mir();
        let basic_block = &mir.basic_blocks()[block];

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            let mut new = Ok(0);
            ConstantExtractor {
                span: stmt.source_info.span,
                substs: self.substs(),
                def_id: self.frame().def_id,
                ecx: self,
                mir: Ref::clone(&mir),
                new_constants: &mut new,
            }.visit_statement(block, stmt, mir::Location { block, statement_index: stmt_id });
            if new? == 0 {
                self.statement(stmt)?;
            }
            // if ConstantExtractor added new frames, we don't execute anything here
            // but await the next call to step
            return Ok(true);
        }

        let terminator = basic_block.terminator();
        let mut new = Ok(0);
        ConstantExtractor {
            span: terminator.source_info.span,
            substs: self.substs(),
            def_id: self.frame().def_id,
            ecx: self,
            mir: Ref::clone(&mir),
            new_constants: &mut new,
        }.visit_terminator(block, terminator, mir::Location { block, statement_index: stmt_id });
        if new? == 0 {
            self.terminator(terminator)?;
        }
        // if ConstantExtractor added new frames, we don't execute anything here
        // but await the next call to step
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", stmt);

        use rustc::mir::StatementKind::*;
        match stmt.kind {
            Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,

            SetDiscriminant { ref lvalue, variant_index } => {
                let dest = self.eval_lvalue(lvalue)?;
                let dest_ty = self.lvalue_ty(lvalue);
                let dest_layout = self.type_layout(dest_ty)?;

                match *dest_layout {
                    Layout::General { discr, ref variants, .. } => {
                        let discr_size = discr.size().bytes();
                        let discr_offset = variants[variant_index].offsets[0].bytes();

                        // FIXME(solson)
                        let dest = self.force_allocation(dest)?;
                        let discr_dest = (dest.to_ptr()).offset(discr_offset);

                        self.memory.write_uint(discr_dest, variant_index as u128, discr_size)?;
                    }

                    Layout::RawNullablePointer { nndiscr, .. } => {
                        use value::PrimVal;
                        if variant_index as u64 != nndiscr {
                            self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
                        }
                    }

                    _ => bug!("SetDiscriminant on {} represented as {:#?}", dest_ty, dest_layout),
                }
            }

            // Miri can safely ignore these. Only translation needs it.
            StorageLive(_) |
            StorageDead(_) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}
        }

        self.frame_mut().stmt += 1;
        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", terminator.kind);
        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            trace!("// {:?}", self.frame().block);
        }
        Ok(())
    }
}

// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
// this includes any method that might access the stack
// basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
    span: Span,
    ecx: &'a mut EvalContext<'b, 'tcx>,
    mir: MirRef<'tcx>,
    def_id: DefId,
    substs: &'tcx subst::Substs<'tcx>,
    new_constants: &'a mut EvalResult<'tcx, u64>,
}

impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
    fn global_item(
        &mut self,
        def_id: DefId,
        substs: &'tcx subst::Substs<'tcx>,
        span: Span,
        shared: bool,
    ) {
        let (def_id, substs) = self.ecx.resolve_associated_const(def_id, substs);
        let cid = GlobalId { def_id, substs, promoted: None };
        if self.ecx.globals.contains_key(&cid) {
            return;
        }
        self.try(|this| {
            let mir = this.ecx.load_mir(def_id)?;
            this.ecx.globals.insert(cid, Global::uninitialized(mir.return_ty));
            let mutable = !shared || mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe();
            let cleanup = StackPopCleanup::MarkStatic(mutable);
            let name = ty::tls::with(|tcx| tcx.item_path_str(def_id));
            trace!("pushing stack frame for global: {}", name);
            this.ecx.push_stack_frame(
                def_id,
                span,
                mir,
                substs,
                Lvalue::Global(cid),
                cleanup,
                Vec::new(),
            )
        });
    }
    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx>>(&mut self, f: F) {
        if let Ok(ref mut n) = *self.new_constants {
            *n += 1;
        } else {
            return;
        }
        if let Err(e) = f(self) {
            *self.new_constants = Err(e);
        }
    }
}

impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
        self.super_constant(constant, location);
        match constant.literal {
            // already computed by rustc
            mir::Literal::Value { .. } => {}
            mir::Literal::Item { def_id, substs } => {
                if let ty::TyFnDef(..) = constant.ty.sty {
                    // No need to do anything here,
                    // because the type is the actual function, not the signature of the function.
                    // Thus we can simply create a zero sized allocation in `evaluate_operand`
                } else {
                    self.global_item(def_id, substs, constant.span, true);
                }
            },
            mir::Literal::Promoted { index } => {
                let cid = GlobalId {
                    def_id: self.def_id,
                    substs: self.substs,
                    promoted: Some(index),
                };
                if self.ecx.globals.contains_key(&cid) {
                    return;
                }
                let mir = Ref::clone(&self.mir);
                let mir = Ref::map(mir, |mir| &mir.promoted[index]);
                self.try(|this| {
                    let ty = this.ecx.monomorphize(mir.return_ty, this.substs);
                    this.ecx.globals.insert(cid, Global::uninitialized(ty));
                    trace!("pushing stack frame for {:?}", index);
                    this.ecx.push_stack_frame(this.def_id,
                                              constant.span,
                                              mir,
                                              this.substs,
                                              Lvalue::Global(cid),
                                              StackPopCleanup::MarkStatic(false),
                                              Vec::new())
                });
            }
        }
    }

    fn visit_lvalue(
        &mut self,
        lvalue: &mir::Lvalue<'tcx>,
        context: LvalueContext<'tcx>,
        location: mir::Location
    ) {
        self.super_lvalue(lvalue, context, location);
        if let mir::Lvalue::Static(def_id) = *lvalue {
            let substs = self.ecx.tcx.intern_substs(&[]);
            let span = self.span;
            if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) {
                if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
                    if let hir::ItemStatic(_, m, _) = *node {
                        self.global_item(def_id, substs, span, m == hir::MutImmutable);
                        return;
                    } else {
                        bug!("static def id doesn't point to static");
                    }
                } else {
                    bug!("static def id doesn't point to item");
                }
            } else {
                let def = self.ecx.tcx.sess.cstore.describe_def(def_id).expect("static not found");
                if let hir::def::Def::Static(_, mutable) = def {
                    self.global_item(def_id, substs, span, !mutable);
                } else {
                    bug!("static found but isn't a static: {:?}", def);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::ffi::CString;
use std::fs::{read_link};
use std::io::{ErrorKind, Error as IoError};
use std::path::{Path};
use std::ptr::null;

use libc::{c_ulong, c_int};
use libmount::{BindMount, Tmpfs};

use path_util::ToCString;

// sys/mount.h
static MS_RDONLY: c_ulong = 1;                /* Mount read-only.  */
static MS_NOSUID: c_ulong = 2;                /* Ignore suid and sgid bits.  */
static MS_NODEV: c_ulong = 4;                 /* Disallow access to device special files.  */
static MS_NOEXEC: c_ulong = 8;                /* Disallow program execution.  */
static MS_SYNCHRONOUS: c_ulong = 16;          /* Writes are synced at once.  */
static MS_REMOUNT: c_ulong = 32;              /* Alter flags of a mounted FS.  */
static MS_MANDLOCK: c_ulong = 64;             /* Allow mandatory locks on an FS.  */
static MS_DIRSYNC: c_ulong = 128;             /* Directory modifications are synchronous.  */
static MS_NOATIME: c_ulong = 1024;            /* Do not update access times.  */
static MS_NODIRATIME: c_ulong = 2048;         /* Do not update directory access times.  */
static MS_BIND: c_ulong = 4096;               /* Bind directory at different place.  */
static MS_MOVE: c_ulong = 8192;
static MS_REC: c_ulong = 16384;
static MS_SILENT: c_ulong = 32768;
static MS_POSIXACL: c_ulong = 1 << 16;        /* VFS does not apply the umask.  */
static MS_UNBINDABLE: c_ulong = 1 << 17;      /* Change to unbindable.  */
static MS_PRIVATE: c_ulong = 1 << 18;         /* Change to private.  */
static MS_SLAVE: c_ulong = 1 << 19;           /* Change to slave.  */
static MS_SHARED: c_ulong = 1 << 20;          /* Change to shared.  */
static MS_RELATIME: c_ulong = 1 << 21;        /* Update atime relative to mtime/ctime.  */
static MS_KERNMOUNT: c_ulong = 1 << 22;       /* This is a kern_mount call.  */
static MS_I_VERSION: c_ulong =  1 << 23;      /* Update inode I_version field.  */
static MS_STRICTATIME: c_ulong = 1 << 24;     /* Always perform atime updates.  */
static MS_ACTIVE: c_ulong = 1 << 30;
static MS_NOUSER: c_ulong = 1 << 31;

static MNT_FORCE: c_int = 1;           /* Force unmounting.  */
static MNT_DETACH: c_int = 2;          /* Just detach from the tree.  */
static MNT_EXPIRE: c_int = 4;          /* Mark for expiry.  */
static UMOUNT_NOFOLLOW: c_int = 8;     /* Don't follow symlink on umount.  */

extern {
    fn mount(source: *const u8, target: *const u8,
        filesystemtype: *const u8, flags: c_ulong,
        data: *const u8) -> c_int;
    fn umount(target: *const u8) -> c_int;
    fn umount2(target: *const u8, flags: c_int) -> c_int;
}

pub fn mount_private(target: &Path) -> Result<(), String> {
    let none = CString::new("none").unwrap();
    let c_target = target.to_cstring();
    debug!("Making private {:?}", target);
    let rc = unsafe { mount(
        none.as_bytes().as_ptr(),
        c_target.as_bytes().as_ptr(),
        null(), MS_PRIVATE, null()) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't make {:?} a slave: {}", target, err));
    }
}

pub fn mount_proc(target: &Path) -> Result<(), String>
{
    let c_target = target.to_cstring();

    // I don't know why we need this flag for mounting proc, but it's somehow
    // works (see https://github.com/tailhook/vagga/issues/12 for the
    // error it fixes)
    let flags = 0xC0ED0000; //MS_MGC_VAL

    debug!("Procfs mount {:?}", target);
    let rc = unsafe { mount(
        b"proc\x00".as_ptr(), c_target.as_bytes().as_ptr(),
        b"proc\x00".as_ptr(), flags, null()) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't mount proc at {:?}: {}",
            target, err));
    }
}

pub fn mount_pseudo(target: &Path, name: &str, options: &str)
    -> Result<(), String>
{
    let c_name = name.to_cstring();
    let c_target = target.to_cstring();
    let c_opts = options.to_cstring();
    // Seems this is similar to why proc is mounted with the flag
    let flags = 0xC0ED0000; //MS_MGC_VAL

    debug!("Pseudofs mount {:?} {} {}", target, name, options);
    let rc = unsafe { mount(
        c_name.as_bytes().as_ptr(),
        c_target.as_bytes().as_ptr(),
        c_name.as_bytes().as_ptr(),
        flags,
        c_opts.as_bytes().as_ptr()) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't mount pseudofs {:?} ({}, options: {}): {}",
            target, options, name, err));
    }
}

#[cfg(not(feature="containers"))]
pub fn unmount(target: &Path) -> Result<(), String> {
    unimplemented!();
}

#[cfg(feature="containers")]
pub fn unmount(target: &Path) -> Result<(), String> {
    let c_target = target.to_cstring();
    let rc = unsafe { umount2(c_target.as_bytes().as_ptr(), MNT_DETACH) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't unmount {:?} : {}", target, err));
    }
}

pub fn mount_system_dirs() -> Result<(), String> {
    mount_dev(Path::new("/vagga/root/dev"))?;
    mount_proc(Path::new("/vagga/root/proc"))?;
    mount_bind(Path::new("/sys"), Path::new("/vagga/root/sys"))?;
    mount_bind(Path::new("/work"), Path::new("/vagga/root/work"))?;
    return Ok(())
}

pub fn unmount_system_dirs() -> Result<(), String> {
    unmount(Path::new("/vagga/root/work"))?;
    unmount(Path::new("/vagga/root/proc"))?;
    unmount(Path::new("/vagga/root/sys"))?;
    unmount(Path::new("/vagga/root/dev"))?;
    Ok(())
}

fn mount_bind(dir: &Path, target_dir: &Path) -> Result<(), String> {
    debug!("Bind mount {:?}", target_dir);
    BindMount::new(dir, &target_dir).mount()
        .map_err(|e| e.to_string())
}

pub fn mount_dev(dev_dir: &Path) -> Result<(), String> {
    mount_bind(Path::new("/dev"), dev_dir)?;

    let pts_dir = dev_dir.join("pts");
    mount_pseudo(&pts_dir, "devpts", "newinstance")?;

    let ptmx_path = dev_dir.join("ptmx");
    match read_link(&ptmx_path) {
        Ok(x) => {
            if Path::new(&x) != Path::new("/dev/pts/ptmx")
               && Path::new(&x) != Path::new("pts/ptmx")
            {
                warn!("The /dev/ptmx refers to {:?}. We need /dev/pts/ptmx \
                    to operate properly. \
                    Probably pseudo-ttys will not work", x);
            }
        }
        Err(ref e) if e.kind() == ErrorKind::InvalidInput => {
            // It's just a device. Let's try bind mount
            mount_bind(&pts_dir.join("ptmx"), &ptmx_path)?;
        }
        Err(e) => {
            warn!("Can't stat /dev/ptmx: {}. \
                Probably pseudo-ttys will not work", e);
        }
    }
    Ok(())
}

pub fn mount_run(run_dir: &Path) -> Result<(), String> {
    debug!("Tmpfs mount {:?}", run_dir);
    Tmpfs::new(&run_dir)
        .size_bytes(100 << 20)
        .mode(0o755)
        .mount().map_err(|e| format!("{}", e))?;
    Ok(())
}
<commit_msg>Fixed missing /run/shm directory<commit_after>#![allow(dead_code)]
use std::ffi::CString;
use std::fs::{read_link};
use std::io::{ErrorKind, Error as IoError};
use std::path::{Path};
use std::ptr::null;

use libc::{c_ulong, c_int};
use libmount::{BindMount, Tmpfs};

use file_util::Dir;
use path_util::ToCString;

// sys/mount.h
static MS_RDONLY: c_ulong = 1;                /* Mount read-only.  */
static MS_NOSUID: c_ulong = 2;                /* Ignore suid and sgid bits.  */
static MS_NODEV: c_ulong = 4;                 /* Disallow access to device special files.  */
static MS_NOEXEC: c_ulong = 8;                /* Disallow program execution.  */
static MS_SYNCHRONOUS: c_ulong = 16;          /* Writes are synced at once.  */
static MS_REMOUNT: c_ulong = 32;              /* Alter flags of a mounted FS.  */
static MS_MANDLOCK: c_ulong = 64;             /* Allow mandatory locks on an FS.  */
static MS_DIRSYNC: c_ulong = 128;             /* Directory modifications are synchronous.  */
static MS_NOATIME: c_ulong = 1024;            /* Do not update access times.  */
static MS_NODIRATIME: c_ulong = 2048;         /* Do not update directory access times.  */
static MS_BIND: c_ulong = 4096;               /* Bind directory at different place.  */
static MS_MOVE: c_ulong = 8192;
static MS_REC: c_ulong = 16384;
static MS_SILENT: c_ulong = 32768;
static MS_POSIXACL: c_ulong = 1 << 16;        /* VFS does not apply the umask.  */
static MS_UNBINDABLE: c_ulong = 1 << 17;      /* Change to unbindable.  */
static MS_PRIVATE: c_ulong = 1 << 18;         /* Change to private.  */
static MS_SLAVE: c_ulong = 1 << 19;           /* Change to slave.  */
static MS_SHARED: c_ulong = 1 << 20;          /* Change to shared.  */
static MS_RELATIME: c_ulong = 1 << 21;        /* Update atime relative to mtime/ctime.  */
static MS_KERNMOUNT: c_ulong = 1 << 22;       /* This is a kern_mount call.  */
static MS_I_VERSION: c_ulong =  1 << 23;      /* Update inode I_version field.  */
static MS_STRICTATIME: c_ulong = 1 << 24;     /* Always perform atime updates.  */
static MS_ACTIVE: c_ulong = 1 << 30;
static MS_NOUSER: c_ulong = 1 << 31;

static MNT_FORCE: c_int = 1;           /* Force unmounting.  */
static MNT_DETACH: c_int = 2;          /* Just detach from the tree.  */
static MNT_EXPIRE: c_int = 4;          /* Mark for expiry.  */
static UMOUNT_NOFOLLOW: c_int = 8;     /* Don't follow symlink on umount.  */

extern {
    fn mount(source: *const u8, target: *const u8,
        filesystemtype: *const u8, flags: c_ulong,
        data: *const u8) -> c_int;
    fn umount(target: *const u8) -> c_int;
    fn umount2(target: *const u8, flags: c_int) -> c_int;
}

pub fn mount_private(target: &Path) -> Result<(), String> {
    let none = CString::new("none").unwrap();
    let c_target = target.to_cstring();
    debug!("Making private {:?}", target);
    let rc = unsafe { mount(
        none.as_bytes().as_ptr(),
        c_target.as_bytes().as_ptr(),
        null(), MS_PRIVATE, null()) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't make {:?} a slave: {}", target, err));
    }
}

pub fn mount_proc(target: &Path) -> Result<(), String>
{
    let c_target = target.to_cstring();

    // I don't know why we need this flag for mounting proc, but it's somehow
    // works (see https://github.com/tailhook/vagga/issues/12 for the
    // error it fixes)
    let flags = 0xC0ED0000; //MS_MGC_VAL

    debug!("Procfs mount {:?}", target);
    let rc = unsafe { mount(
        b"proc\x00".as_ptr(), c_target.as_bytes().as_ptr(),
        b"proc\x00".as_ptr(), flags, null()) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't mount proc at {:?}: {}",
            target, err));
    }
}

pub fn mount_pseudo(target: &Path, name: &str, options: &str)
    -> Result<(), String>
{
    let c_name = name.to_cstring();
    let c_target = target.to_cstring();
    let c_opts = options.to_cstring();
    // Seems this is similar to why proc is mounted with the flag
    let flags = 0xC0ED0000; //MS_MGC_VAL

    debug!("Pseudofs mount {:?} {} {}", target, name, options);
    let rc = unsafe { mount(
        c_name.as_bytes().as_ptr(),
        c_target.as_bytes().as_ptr(),
        c_name.as_bytes().as_ptr(),
        flags,
        c_opts.as_bytes().as_ptr()) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't mount pseudofs {:?} ({}, options: {}): {}",
            target, options, name, err));
    }
}

#[cfg(not(feature="containers"))]
pub fn unmount(target: &Path) -> Result<(), String> {
    unimplemented!();
}

#[cfg(feature="containers")]
pub fn unmount(target: &Path) -> Result<(), String> {
    let c_target = target.to_cstring();
    let rc = unsafe { umount2(c_target.as_bytes().as_ptr(), MNT_DETACH) };
    if rc == 0 {
        return Ok(());
    } else {
        let err = IoError::last_os_error();
        return Err(format!("Can't unmount {:?} : {}", target, err));
    }
}

pub fn mount_system_dirs() -> Result<(), String> {
    mount_dev(Path::new("/vagga/root/dev"))?;
    mount_proc(Path::new("/vagga/root/proc"))?;
    mount_bind(Path::new("/sys"), Path::new("/vagga/root/sys"))?;
    mount_bind(Path::new("/work"), Path::new("/vagga/root/work"))?;
    return Ok(())
}

pub fn unmount_system_dirs() -> Result<(), String> {
    unmount(Path::new("/vagga/root/work"))?;
    unmount(Path::new("/vagga/root/proc"))?;
    unmount(Path::new("/vagga/root/sys"))?;
    unmount(Path::new("/vagga/root/dev"))?;
    Ok(())
}

fn mount_bind(dir: &Path, target_dir: &Path) -> Result<(), String> {
    debug!("Bind mount {:?}", target_dir);
    BindMount::new(dir, &target_dir).mount()
        .map_err(|e| e.to_string())
}

pub fn mount_dev(dev_dir: &Path) -> Result<(), String> {
    mount_bind(Path::new("/dev"), dev_dir)?;

    let pts_dir = dev_dir.join("pts");
    mount_pseudo(&pts_dir, "devpts", "newinstance")?;

    let ptmx_path = dev_dir.join("ptmx");
    match read_link(&ptmx_path) {
        Ok(x) => {
            if Path::new(&x) != Path::new("/dev/pts/ptmx")
               && Path::new(&x) != Path::new("pts/ptmx")
            {
                warn!("The /dev/ptmx refers to {:?}. We need /dev/pts/ptmx \
                    to operate properly. \
                    Probably pseudo-ttys will not work", x);
            }
        }
        Err(ref e) if e.kind() == ErrorKind::InvalidInput => {
            // It's just a device. Let's try bind mount
            mount_bind(&pts_dir.join("ptmx"), &ptmx_path)?;
        }
        Err(e) => {
            warn!("Can't stat /dev/ptmx: {}. \
                Probably pseudo-ttys will not work", e);
        }
    }
    Ok(())
}

pub fn mount_run(run_dir: &Path) -> Result<(), String> {
    debug!("Tmpfs mount {:?}", run_dir);
    Tmpfs::new(&run_dir)
        .size_bytes(100 << 20)
        .mode(0o755)
        .mount().map_err(|e| format!("{}", e))?;
    // We should create /run/shm directory since
    // some systems have /dev/shm as a symlink to the /run/shm
    try_msg!(Dir::new(&run_dir.join("shm")).mode(0o1777).create(),
        "Error creating /vagga/root/run/shm: {err}");
    Ok(())
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug, PartialEq)]
pub enum Atom {
    Nil,
    True,
    False,
    UserDefined(String)
}

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    Atom(Atom),
    Integer(i64),
}
<commit_msg>Add a Float term<commit_after>#[derive(Clone, Debug, PartialEq)]
pub enum Atom {
    Nil,
    True,
    False,
    UserDefined(String)
}

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    Atom(Atom),
    Integer(i64),
    Float(f64),
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

use {Action, InputTranslator, RebindBuilder, InputRebind};
use window::Size;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum TestAction {
    Action1, Action2, Action3, Action4, Action5,
    Action6, Action7, Action8, Action9, Action10
}

impl Action for TestAction { }

type TestBuilder = RebindBuilder<TestAction>;
type TestTranslator = InputTranslator<TestAction>;
type TestRebind = InputRebind<TestAction>;

const TEST_SIZE: Size = Size {
    width:  800,
    height: 600
};

fn create_prepopulated_builder() -> TestBuilder {
    use input::keyboard::Key;
    use input::Button::Keyboard;

    RebindBuilder::new(TEST_SIZE)
        .with_action_mapping(Keyboard(Key::Up),    TestAction::Action1)
        .with_action_mapping(Keyboard(Key::W),     TestAction::Action1)
        .with_action_mapping(Keyboard(Key::Down),  TestAction::Action2)
        .with_action_mapping(Keyboard(Key::S),     TestAction::Action2)
        .with_action_mapping(Keyboard(Key::Left),  TestAction::Action3)
        .with_action_mapping(Keyboard(Key::A),     TestAction::Action3)
        .with_action_mapping(Keyboard(Key::Right), TestAction::Action4)
        .with_action_mapping(Keyboard(Key::D),     TestAction::Action4)
}

#[test]
fn test_empty() {
    let builder = TestBuilder::new(TEST_SIZE).build();
}

#[test]
fn test_conversion_from_rebind_to_translator() {
    let translator: TestTranslator = create_prepopulated_builder().build();
    let translator_clone = translator.clone();
    let converted_translator: TestTranslator = {
        let rebind: TestRebind = translator.into();
        rebind.into()
    };

    assert_eq!(converted_translator, translator_clone);
}
<commit_msg>Remove unnecessary type annotation<commit_after>#![allow(dead_code, unused_variables)]

use {Action, InputTranslator, RebindBuilder, InputRebind};
use window::Size;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum TestAction {
    Action1, Action2, Action3, Action4, Action5,
    Action6, Action7, Action8, Action9, Action10
}

impl Action for TestAction { }

type TestBuilder = RebindBuilder<TestAction>;
type TestTranslator = InputTranslator<TestAction>;
type TestRebind = InputRebind<TestAction>;

const TEST_SIZE: Size = Size {
    width:  800,
    height: 600
};

fn create_prepopulated_builder() -> TestBuilder {
    use input::keyboard::Key;
    use input::Button::Keyboard;

    RebindBuilder::new(TEST_SIZE)
        .with_action_mapping(Keyboard(Key::Up),    TestAction::Action1)
        .with_action_mapping(Keyboard(Key::W),     TestAction::Action1)
        .with_action_mapping(Keyboard(Key::Down),  TestAction::Action2)
        .with_action_mapping(Keyboard(Key::S),     TestAction::Action2)
        .with_action_mapping(Keyboard(Key::Left),  TestAction::Action3)
        .with_action_mapping(Keyboard(Key::A),     TestAction::Action3)
        .with_action_mapping(Keyboard(Key::Right), TestAction::Action4)
        .with_action_mapping(Keyboard(Key::D),     TestAction::Action4)
}

#[test]
fn test_empty() {
    let builder = TestBuilder::new(TEST_SIZE).build();
}

#[test]
fn test_conversion_from_rebind_to_translator() {
    let translator: TestTranslator = create_prepopulated_builder().build();
    let translator_clone = translator.clone();
    let converted_translator: TestTranslator = {
        let rebind = translator.into();
        rebind.into()
    };

    assert_eq!(converted_translator, translator_clone);
}
<|endoftext|>