<commit_before>use libaio::{self, aio_context_t, io_event, iocb};
use libc::{self, c_int, c_uint, c_void};
use nix;
use std::collections::BTreeMap;
use std::error::Error;
use std::ptr;
use std::slice;
use std::fs::{File, OpenOptions};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;

const MAX_EVENTS: c_int = 32;

// Meaning of block/sector sizes:
//
// physical block size - true physical block size of hardware
// sector size - minimum size of reads and writes supported by hardware (potentially smaller than
// physical block size)
// (logical) block size - a value that may actually vary across partitions, depending on whether a filesystem
// is mounted
//
// Alignment for O_DIRECT:
//
// In 2.4: buffer offset and transfer size must be multiples of logical block size.
// In 2.5: buffer offset and transfer size must be multiples of sector size.
//
// See https://lists.gt.net/linux/kernel/350775

#[derive(Debug)]
pub struct BlockDevice {
    block_size_physical: usize,
    context: aio_context_t,
    file: File,
    iocbs: Vec<(bool, iocb)>,
    requests: BTreeMap<usize, Request>,
    sector_size: usize,
    size_bytes: u64,
}

mod ioctl {
    use libc::c_uint;
    pub const BLK: c_uint = 0x12;
    pub const SSZGET: c_uint = 104;
    pub const GETSIZE64: c_uint = 114;
    pub const PBSZGET: c_uint = 123;
}

#[derive(Debug)]
pub struct Request {
    pub offset: u64,
    pub size: u64,
    pub buffer: Buffer,
    pub result: isize,
}

impl Request {
    pub fn new(offset: u64, size: u64, buffer: Buffer) -> Request {
        assert!(buffer.size as u64 >= size, "Supplied buffer is too small");
        Request {
            offset: offset,
            size: size,
            buffer: buffer,
            result: -1,
        }
    }

    pub fn get_data(&self) -> &[u8] {
        if self.result < 0 {
            &[]
        } else {
            &self.buffer.as_slice()[0..(self.result as usize)]
        }
    }

    pub fn reclaim_buffer(self) -> Buffer {
        self.buffer
    }

    pub fn is_data_zeros(&self) -> bool {
        for c in self.get_data() {
            if *c != 0 {
                return false;
            }
        }
        return true;
    }
}

#[derive(Debug)]
pub struct Buffer {
    alignment: usize,
    size: usize,
    data: *mut c_void,
}

impl Buffer {
    pub fn allocate_aligned(size: usize, alignment: usize) -> Buffer {
        let buffer = unsafe { libc::memalign(alignment, size) };
        if buffer.is_null() {
            panic!("Buffer allocation failed!");
        }
        Buffer {
            alignment: alignment,
            size: size,
            data: buffer,
        }
    }

    pub fn len(&self) -> usize {
        self.size
    }

    pub fn as_slice(&self) -> &[u8] {
        unsafe {
            let data = self.data as *const u8;
            slice::from_raw_parts(data, self.size)
        }
    }

    pub fn clear(&mut self) {
        unsafe {
            libc::memset(self.data, 0, self.size);
        }
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            libc::free(self.data);
        }
    }
}

impl BlockDevice {
    pub fn open(path: &str) -> Result<BlockDevice, Box<Error>> {
        let file = OpenOptions::new()
            .read(true)
            .write(false)
            .custom_flags(libc::O_DIRECT)
            .open(path)?;
        let fd = file.as_raw_fd();
        let block_size_physical = Self::query_block_size_physical(fd)?;
        let sector_size = Self::query_sector_size(fd)?;
        let size_bytes = Self::query_size_bytes(fd)?;
        let iocbs = vec![(false, iocb::new()); MAX_EVENTS as usize];
        let mut context: aio_context_t = ptr::null_mut();
        if unsafe { libaio::io_setup(iocbs.len() as i32, &mut context as *mut aio_context_t) } == -1 {
            return Err(Box::new(Self::fail_errno()));
        }

        let result = BlockDevice {
            context: context,
            block_size_physical: block_size_physical as usize,
            file: file,
            iocbs: iocbs,
            requests: BTreeMap::new(),
            size_bytes: size_bytes,
            sector_size: sector_size as usize,
        };
        Ok(result)
    }

    fn get_fd(&self) -> c_int {
        self.file.as_raw_fd()
    }

    fn query_block_size_physical(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut block_size_physical: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::PBSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut block_size_physical as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(block_size_physical)
        }
    }

    fn query_sector_size(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut sector_size: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::SSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut sector_size as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(sector_size)
        }
    }

    fn query_size_bytes(fd: c_int) -> Result<u64, nix::Error> {
        let mut size_bytes: u64 = 0;
        let ioc = ior!(ioctl::BLK, ioctl::GETSIZE64, 8);
        if unsafe { libc::ioctl(fd, ioc, &mut size_bytes as *mut u64) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(size_bytes)
        }
    }

    pub fn submit_request(&mut self, req: Request) -> Result<(), nix::Error> {
        assert!(self.requests_avail() > 0);
        let fd = self.get_fd();
        let slot = self.find_slot();
        let iocb = &mut self.iocbs[slot];
        iocb.0 = true;
        libaio::io_prep_pread(&mut iocb.1, fd as u32, req.buffer.data, req.size, req.offset as i64);
        let iocb_ptr = &mut iocb.1 as *mut iocb;
        let mut iocb_list = [iocb_ptr];
        let res = unsafe {
            libaio::io_submit(self.context, iocb_list.len() as i64, &mut iocb_list[0] as *mut *mut iocb)
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            self.requests.insert(slot, req);
            Ok(())
        }
    }

    pub fn get_completed_request(&mut self) -> Result<Request, nix::Error> {
        let mut event = io_event::new();
        let res = unsafe {
            libaio::io_getevents(self.context, 1, 1, &mut event as *mut io_event, ptr::null_mut())
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            for (idx, &mut (ref mut used, ref mut cb)) in self.iocbs.iter_mut().enumerate() {
                if event.obj == cb as *mut iocb as u64 {
                    *used = false;
                    let mut req = self.requests.remove(&idx).unwrap();
                    req.result = event.res as isize;
                    return Ok(req);
                }
            }
            panic!("Couldn't find iocb for completed request!");
        }
    }

    fn find_slot(&self) -> usize {
        for (idx, &(used, _)) in self.iocbs.iter().enumerate() {
            if !used {
                return idx;
            }
        }
        panic!("No free slot");
    }

    pub fn get_block_size_physical(&self) -> usize {
        self.block_size_physical
    }

    pub fn get_sector_size(&self) -> usize {
        self.sector_size
    }

    pub fn get_size_bytes(&self) -> u64 {
        self.size_bytes
    }

    fn fail_errno() -> nix::Error {
        nix::Error::last()
    }

    pub fn max_requests(&self) -> usize {
        self.iocbs.len()
    }

    pub fn requests_avail(&self) -> usize {
        self.iocbs.iter().filter(|r| !r.0).count()
    }

    pub fn requests_pending(&self) -> usize {
        self.iocbs.iter().filter(|r| r.0).count()
    }

    pub fn create_io_buffer(&self, sectors: usize) -> Buffer {
        let bytes = sectors * self.sector_size;
        Buffer::allocate_aligned(bytes, self.sector_size)
    }
}

impl Drop for BlockDevice {
    fn drop(&mut self) {
        unsafe {
            libaio::io_destroy(self.context);
        };
    }
}
<commit_msg>Add assertion.<commit_after>use libaio::{self, aio_context_t, io_event, iocb};
use libc::{self, c_int, c_uint, c_void};
use nix;
use std::collections::BTreeMap;
use std::error::Error;
use std::ptr;
use std::slice;
use std::fs::{File, OpenOptions};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;

const MAX_EVENTS: c_int = 32;

// Meaning of block/sector sizes:
//
// physical block size - true physical block size of hardware
// sector size - minimum size of reads and writes supported by hardware (potentially smaller than
// physical block size)
// (logical) block size - a value that may actually vary across partitions, depending on whether a filesystem
// is mounted
//
// Alignment for O_DIRECT:
//
// In 2.4: buffer offset and transfer size must be multiples of logical block size.
// In 2.5: buffer offset and transfer size must be multiples of sector size.
//
// See https://lists.gt.net/linux/kernel/350775

#[derive(Debug)]
pub struct BlockDevice {
    block_size_physical: usize,
    context: aio_context_t,
    file: File,
    iocbs: Vec<(bool, iocb)>,
    requests: BTreeMap<usize, Request>,
    sector_size: usize,
    size_bytes: u64,
}

mod ioctl {
    use libc::c_uint;
    pub const BLK: c_uint = 0x12;
    pub const SSZGET: c_uint = 104;
    pub const GETSIZE64: c_uint = 114;
    pub const PBSZGET: c_uint = 123;
}

#[derive(Debug)]
pub struct Request {
    pub offset: u64,
    pub size: u64,
    pub buffer: Buffer,
    pub result: isize,
}

impl Request {
    pub fn new(offset: u64, size: u64, buffer: Buffer) -> Request {
        assert!(buffer.size as u64 >= size, "Supplied buffer is too small");
        Request {
            offset: offset,
            size: size,
            buffer: buffer,
            result: -1,
        }
    }

    pub fn get_data(&self) -> &[u8] {
        if self.result < 0 {
            &[]
        } else {
            &self.buffer.as_slice()[0..(self.result as usize)]
        }
    }

    pub fn reclaim_buffer(self) -> Buffer {
        self.buffer
    }

    pub fn is_data_zeros(&self) -> bool {
        for c in self.get_data() {
            if *c != 0 {
                return false;
            }
        }
        return true;
    }
}

#[derive(Debug)]
pub struct Buffer {
    alignment: usize,
    size: usize,
    data: *mut c_void,
}

impl Buffer {
    pub fn allocate_aligned(size: usize, alignment: usize) -> Buffer {
        let buffer = unsafe { libc::memalign(alignment, size) };
        if buffer.is_null() {
            panic!("Buffer allocation failed!");
        }
        Buffer {
            alignment: alignment,
            size: size,
            data: buffer,
        }
    }

    pub fn len(&self) -> usize {
        self.size
    }

    pub fn as_slice(&self) -> &[u8] {
        unsafe {
            let data = self.data as *const u8;
            slice::from_raw_parts(data, self.size)
        }
    }

    pub fn clear(&mut self) {
        unsafe {
            libc::memset(self.data, 0, self.size);
        }
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            libc::free(self.data);
        }
    }
}

impl BlockDevice {
    pub fn open(path: &str) -> Result<BlockDevice, Box<Error>> {
        let file = OpenOptions::new()
            .read(true)
            .write(false)
            .custom_flags(libc::O_DIRECT)
            .open(path)?;
        let fd = file.as_raw_fd();
        let block_size_physical = Self::query_block_size_physical(fd)?;
        let sector_size = Self::query_sector_size(fd)?;
        let size_bytes = Self::query_size_bytes(fd)?;
        let iocbs = vec![(false, iocb::new()); MAX_EVENTS as usize];
        let mut context: aio_context_t = ptr::null_mut();
        if unsafe { libaio::io_setup(iocbs.len() as i32, &mut context as *mut aio_context_t) } == -1 {
            return Err(Box::new(Self::fail_errno()));
        }

        let result = BlockDevice {
            context: context,
            block_size_physical: block_size_physical as usize,
            file: file,
            iocbs: iocbs,
            requests: BTreeMap::new(),
            size_bytes: size_bytes,
            sector_size: sector_size as usize,
        };
        Ok(result)
    }

    fn get_fd(&self) -> c_int {
        self.file.as_raw_fd()
    }

    fn query_block_size_physical(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut block_size_physical: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::PBSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut block_size_physical as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(block_size_physical)
        }
    }

    fn query_sector_size(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut sector_size: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::SSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut sector_size as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(sector_size)
        }
    }

    fn query_size_bytes(fd: c_int) -> Result<u64, nix::Error> {
        let mut size_bytes: u64 = 0;
        let ioc = ior!(ioctl::BLK, ioctl::GETSIZE64, 8);
        if unsafe { libc::ioctl(fd, ioc, &mut size_bytes as *mut u64) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(size_bytes)
        }
    }

    pub fn submit_request(&mut self, req: Request) -> Result<(), nix::Error> {
        assert!(self.requests_avail() > 0);
        let fd = self.get_fd();
        let slot = self.find_slot();
        let iocb = &mut self.iocbs[slot];
        iocb.0 = true;
        libaio::io_prep_pread(&mut iocb.1, fd as u32, req.buffer.data, req.size, req.offset as i64);
        let iocb_ptr = &mut iocb.1 as *mut iocb;
        let mut iocb_list = [iocb_ptr];
        let res = unsafe {
            libaio::io_submit(self.context, iocb_list.len() as i64, &mut iocb_list[0] as *mut *mut iocb)
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            self.requests.insert(slot, req);
            Ok(())
        }
    }

    pub fn get_completed_request(&mut self) -> Result<Request, nix::Error> {
        assert!(self.requests_pending() > 0);
        let mut event = io_event::new();
        let res = unsafe {
            libaio::io_getevents(self.context, 1, 1, &mut event as *mut io_event, ptr::null_mut())
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            for (idx, &mut (ref mut used, ref mut cb)) in self.iocbs.iter_mut().enumerate() {
                if event.obj == cb as *mut iocb as u64 {
                    *used = false;
                    let mut req = self.requests.remove(&idx).unwrap();
                    req.result = event.res as isize;
                    return Ok(req);
                }
            }
            panic!("Couldn't find iocb for completed request!");
        }
    }

    fn find_slot(&self) -> usize {
        for (idx, &(used, _)) in self.iocbs.iter().enumerate() {
            if !used {
                return idx;
            }
        }
        panic!("No free slot");
    }

    pub fn get_block_size_physical(&self) -> usize {
        self.block_size_physical
    }

    pub fn get_sector_size(&self) -> usize {
        self.sector_size
    }

    pub fn get_size_bytes(&self) -> u64 {
        self.size_bytes
    }

    fn fail_errno() -> nix::Error {
        nix::Error::last()
    }

    pub fn max_requests(&self) -> usize {
        self.iocbs.len()
    }

    pub fn requests_avail(&self) -> usize {
        self.iocbs.iter().filter(|r| !r.0).count()
    }

    pub fn requests_pending(&self) -> usize {
        self.iocbs.iter().filter(|r| r.0).count()
    }

    pub fn create_io_buffer(&self, sectors: usize) -> Buffer {
        let bytes = sectors * self.sector_size;
        Buffer::allocate_aligned(bytes, self.sector_size)
    }
}

impl Drop for BlockDevice {
    fn drop(&mut self) {
        unsafe {
            libaio::io_destroy(self.context);
        };
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::fmt::{Display, Error, Formatter};
use action::{POSSIBLE_DIRECTIONS,POSSIBLE_MOVE_TYPES,Coordinate,Move};

pub const NUM_COLS: usize = 5;
pub const NUM_ROWS: usize = 4;

// Hacks for the three states of the lower-left of the board in JunSeok vs YeonSeung game
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum BoardType {
    Left,
    LeftOrMiddle,
    Middle,
    RightOrMiddle,
    Right,
}

impl BoardType {
    fn is_final(&self) -> bool {
        match *self {
            BoardType::Left => true,
            BoardType::Middle => true,
            BoardType::Right => true,
            BoardType::LeftOrMiddle => false,
            BoardType::RightOrMiddle => false,
        }
    }

    // Can a board of type `current` become this type?
    fn applies_to(&self, current: Option<BoardType>) -> bool {
        match (current, *self) {
            // a none board type can change to anything.
            (None, _) => true,
            // LeftOrMiddle can change to itself, left, or middle.
            (Some(BoardType::LeftOrMiddle), BoardType::LeftOrMiddle) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Left) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::LeftOrMiddle), _) => false,
            // RightOrMiddle can change to itself, right, or middle.
            (Some(BoardType::RightOrMiddle), BoardType::RightOrMiddle) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Right) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::RightOrMiddle), _) => false,
            // Left, Middle, Right can change to themselves only.
            (Some(BoardType::Left), BoardType::Left) => true,
            (Some(BoardType::Left), _) => false,
            (Some(BoardType::Middle), BoardType::Middle) => true,
            (Some(BoardType::Middle), _) => false,
            (Some(BoardType::Right), BoardType::Right) => true,
            (Some(BoardType::Right), _) => false,
        }
    }

    fn induced_by(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match *self {
            BoardType::Left          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            BoardType::LeftOrMiddle  => c == Coordinate{row: 1, col: 0},
            BoardType::Middle        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            BoardType::RightOrMiddle => c == Coordinate{row: 3, col: 1},
            BoardType::Right         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
        }
    }
}

const POSSIBLE_BOARD_TYPES: [BoardType; 5] = [
    BoardType::Left,
    BoardType::LeftOrMiddle,
    BoardType::Middle,
    BoardType::RightOrMiddle,
    BoardType::Right,
];

pub type BoardArray = [[bool; NUM_COLS]; NUM_ROWS];
pub struct Board {
    board: BoardArray,
    board_type: Option<BoardType>,
}

impl Board {
    pub fn new(array: BoardArray, board_type: Option<BoardType>) -> Board {
        Board{board: array, board_type: board_type}
    }

    pub fn make_move(&mut self, m: Move) {
        if let Some(bt) = m.new_board_type {
            if !bt.applies_to(self.board_type) {
                panic!("Board type is {:?}, not compatible with {:?}", self.board_type, bt);
            }
            self.board_type = m.new_board_type
        }
        self.set_squares(m, true)
    }

    pub fn undo_move(&mut self, m: Move) {
        self.board_type = m.old_board_type;
        self.set_squares(m, false)
    }

    fn set_squares(&mut self, m: Move, mode: bool) {
        self.board[m.coord.row][m.coord.col] = mode;
        for other_space in m.extensions().iter() {
            self.board[other_space.row][other_space.col] = mode;
        }
    }

    fn occupied(&self, c: Coordinate) -> bool {
        self.board[c.row][c.col]
    }

    // This assesses whether a coordinate can be placed on the board,
    // given the current type of the board.
    fn compatible(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match self.board_type {
            Some(BoardType::Left)          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::LeftOrMiddle)  => c != Coordinate{row: 1, col: 1},
            Some(BoardType::Middle)        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::RightOrMiddle) => c != Coordinate{row: 3, col: 0},
            Some(BoardType::Right)         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
            None => true,
        }
    }

    fn frontier(&self) -> Vec<Coordinate> {
        let mut results = Vec::new();
        for row in 0..NUM_ROWS {
            for col in 0..NUM_COLS {
                let coord = Coordinate{row: row, col: col};
                if self.occupied(coord) || !self.compatible(coord) {
                    continue;
                }
                let have_neighbor = POSSIBLE_DIRECTIONS.iter().any(|dir| {
                    if let Some(dest) = coord.move_in(*dir, 1) { self.occupied(dest) } else { false }
                });
                if have_neighbor {
                    results.push(coord);
                }
            }
        }
        results
    }

    fn board_type_final(&self) -> bool {
        if let Some(x) = self.board_type { x.is_final() } else { false }
    }

    pub fn legal_moves(&self) -> Vec<Move> {
        let mut results = Vec::new();
        for frontier_space in self.frontier().iter() {
            for move_type in POSSIBLE_MOVE_TYPES.iter() {
                let mov = match Move::new(*frontier_space, *move_type, self.board_type) {
                    Some(x) => x,
                    None => continue,
                };
                let mut other_space_taken = false;
                let mut induces_board_type = frontier_space.induces_board_type();
                for other_space in mov.extensions().iter() {
                    if other_space.induces_board_type() {
                        induces_board_type = true;
                    }
                    if self.occupied(*other_space) || !self.compatible(*other_space) {
                        other_space_taken = true;
                        break;
                    }
                }
                if other_space_taken {
                    continue;
                }

                if !induces_board_type || self.board_type_final() {
                    results.push(mov);
                    continue;
                }

                let mut ok_board_types: BTreeSet<_> = POSSIBLE_BOARD_TYPES.iter().cloned().filter(|board_type| {
                    board_type.applies_to(self.board_type) &&
                        board_type.induced_by(*frontier_space) &&
                        mov.extensions().iter().all(|coord| board_type.induced_by(*coord))
                }).collect();

                // Dominated board types...
                if ok_board_types.contains(&BoardType::LeftOrMiddle) {
                    ok_board_types.remove(&BoardType::Left);
                    ok_board_types.remove(&BoardType::Middle);
                }
                if ok_board_types.contains(&BoardType::RightOrMiddle) {
                    ok_board_types.remove(&BoardType::Right);
                    ok_board_types.remove(&BoardType::Middle);
                }

                for board_type in ok_board_types.iter() {
                    results.push(mov.with_board_type(*board_type));
                }
            }
        }
        results
    }
}

impl Display for Board {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        // Print header row
        try!(formatter.write_str("    "));
        for i in 0..NUM_COLS {
            try!(write!(formatter, " {}", i));
        }
        try!(formatter.write_str("\n"));

        // Print top box border
        try!(formatter.write_str("    ┌─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┬─"));
        }
        try!(formatter.write_str("┐\n"));

        for (i, row) in self.board.iter().enumerate() {
            // Print cell content
            try!(write!(formatter, "{: >2}  │", i));
            for col in row.iter() {
                let chr = if *col { "x" } else { " " };
                try!(write!(formatter, "{}│", chr));
            }
            try!(formatter.write_str("\n"));

            // Print box border between rows
            if i != NUM_ROWS - 1 {
                try!(formatter.write_str("    ├─"));
                for _ in 0..NUM_COLS - 1 {
                    try!(formatter.write_str("┼─"));
                }
                try!(formatter.write_str("┤\n"));
            }
        }

        // Print bottom box border
        try!(formatter.write_str("    └─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┴─"));
        }
        try!(formatter.write_str("┘\n"));

        write!(formatter, "{:?}", self.board_type)
    }
}
<commit_msg>Add Orientations for pieces<commit_after>use std::collections::BTreeSet;
use std::fmt::{Display, Error, Formatter};
use action::{POSSIBLE_DIRECTIONS,POSSIBLE_MOVE_TYPES,Coordinate,Move};

pub const NUM_COLS: usize = 5;
pub const NUM_ROWS: usize = 4;

// Hacks for the three states of the lower-left of the board in JunSeok vs YeonSeung game
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum BoardType {
    Left,
    LeftOrMiddle,
    Middle,
    RightOrMiddle,
    Right,
}

impl BoardType {
    fn is_final(&self) -> bool {
        match *self {
            BoardType::Left => true,
            BoardType::Middle => true,
            BoardType::Right => true,
            BoardType::LeftOrMiddle => false,
            BoardType::RightOrMiddle => false,
        }
    }

    // Can a board of type `current` become this type?
    fn applies_to(&self, current: Option<BoardType>) -> bool {
        match (current, *self) {
            // a none board type can change to anything.
            (None, _) => true,
            // LeftOrMiddle can change to itself, left, or middle.
            (Some(BoardType::LeftOrMiddle), BoardType::LeftOrMiddle) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Left) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::LeftOrMiddle), _) => false,
            // RightOrMiddle can change to itself, right, or middle.
            (Some(BoardType::RightOrMiddle), BoardType::RightOrMiddle) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Right) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::RightOrMiddle), _) => false,
            // Left, Middle, Right can change to themselves only.
            (Some(BoardType::Left), BoardType::Left) => true,
            (Some(BoardType::Left), _) => false,
            (Some(BoardType::Middle), BoardType::Middle) => true,
            (Some(BoardType::Middle), _) => false,
            (Some(BoardType::Right), BoardType::Right) => true,
            (Some(BoardType::Right), _) => false,
        }
    }

    fn induced_by(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match *self {
            BoardType::Left          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            BoardType::LeftOrMiddle  => c == Coordinate{row: 1, col: 0},
            BoardType::Middle        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            BoardType::RightOrMiddle => c == Coordinate{row: 3, col: 1},
            BoardType::Right         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
        }
    }
}

#[derive(Copy, Clone)]
enum Orientation {
    UpDown,
    LeftRight,
    UpLeft,
    UpRight,
    DownLeft,
    DownRight,
}

impl Orientation {
    fn to_str(&self) -> &'static str {
        match *self {
            Orientation::UpDown => "║",
            Orientation::LeftRight => "═",
            Orientation::UpLeft => "╝",
            Orientation::UpRight => "╚",
            Orientation::DownLeft => "╗",
            Orientation::DownRight => "╔",
        }
    }
}

const POSSIBLE_BOARD_TYPES: [BoardType; 5] = [
    BoardType::Left,
    BoardType::LeftOrMiddle,
    BoardType::Middle,
    BoardType::RightOrMiddle,
    BoardType::Right,
];

pub type BoardArray = [[bool; NUM_COLS]; NUM_ROWS];
pub struct Board {
    board: BoardArray,
    board_type: Option<BoardType>,
}

impl Board {
    pub fn new(array: BoardArray, board_type: Option<BoardType>) -> Board {
        Board{board: array, board_type: board_type}
    }

    pub fn make_move(&mut self, m: Move) {
        if let Some(bt) = m.new_board_type {
            if !bt.applies_to(self.board_type) {
                panic!("Board type is {:?}, not compatible with {:?}", self.board_type, bt);
            }
            self.board_type = m.new_board_type
        }
        self.set_squares(m, true)
    }

    pub fn undo_move(&mut self, m: Move) {
        self.board_type = m.old_board_type;
        self.set_squares(m, false)
    }

    fn set_squares(&mut self, m: Move, mode: bool) {
        self.board[m.coord.row][m.coord.col] = mode;
        for other_space in m.extensions().iter() {
            self.board[other_space.row][other_space.col] = mode;
        }
    }

    fn occupied(&self, c: Coordinate) -> bool {
        self.board[c.row][c.col]
    }

    // This assesses whether a coordinate can be placed on the board,
    // given the current type of the board.
    fn compatible(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match self.board_type {
            Some(BoardType::Left)          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::LeftOrMiddle)  => c != Coordinate{row: 1, col: 1},
            Some(BoardType::Middle)        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::RightOrMiddle) => c != Coordinate{row: 3, col: 0},
            Some(BoardType::Right)         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
            None => true,
        }
    }

    fn frontier(&self) -> Vec<Coordinate> {
        let mut results = Vec::new();
        for row in 0..NUM_ROWS {
            for col in 0..NUM_COLS {
                let coord = Coordinate{row: row, col: col};
                if self.occupied(coord) || !self.compatible(coord) {
                    continue;
                }
                let have_neighbor = POSSIBLE_DIRECTIONS.iter().any(|dir| {
                    if let Some(dest) = coord.move_in(*dir, 1) { self.occupied(dest) } else { false }
                });
                if have_neighbor {
                    results.push(coord);
                }
            }
        }
        results
    }

    fn board_type_final(&self) -> bool {
        if let Some(x) = self.board_type { x.is_final() } else { false }
    }

    pub fn legal_moves(&self) -> Vec<Move> {
        let mut results = Vec::new();
        for frontier_space in self.frontier().iter() {
            for move_type in POSSIBLE_MOVE_TYPES.iter() {
                let mov = match Move::new(*frontier_space, *move_type, self.board_type) {
                    Some(x) => x,
                    None => continue,
                };
                let mut other_space_taken = false;
                let mut induces_board_type = frontier_space.induces_board_type();
                for other_space in mov.extensions().iter() {
                    if other_space.induces_board_type() {
                        induces_board_type = true;
                    }
                    if self.occupied(*other_space) || !self.compatible(*other_space) {
                        other_space_taken = true;
                        break;
                    }
                }
                if other_space_taken {
                    continue;
                }

                if !induces_board_type || self.board_type_final() {
                    results.push(mov);
                    continue;
                }

                let mut ok_board_types: BTreeSet<_> = POSSIBLE_BOARD_TYPES.iter().cloned().filter(|board_type| {
                    board_type.applies_to(self.board_type) &&
                        board_type.induced_by(*frontier_space) &&
                        mov.extensions().iter().all(|coord| board_type.induced_by(*coord))
                }).collect();

                // Dominated board types...
                if ok_board_types.contains(&BoardType::LeftOrMiddle) {
                    ok_board_types.remove(&BoardType::Left);
                    ok_board_types.remove(&BoardType::Middle);
                }
                if ok_board_types.contains(&BoardType::RightOrMiddle) {
                    ok_board_types.remove(&BoardType::Right);
                    ok_board_types.remove(&BoardType::Middle);
                }

                for board_type in ok_board_types.iter() {
                    results.push(mov.with_board_type(*board_type));
                }
            }
        }
        results
    }
}

impl Display for Board {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        // Print header row
        try!(formatter.write_str("    "));
        for i in 0..NUM_COLS {
            try!(write!(formatter, " {}", i));
        }
        try!(formatter.write_str("\n"));

        // Print top box border
        try!(formatter.write_str("    ┌─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┬─"));
        }
        try!(formatter.write_str("┐\n"));

        for (i, row) in self.board.iter().enumerate() {
            // Print cell content
            try!(write!(formatter, "{: >2}  │", i));
            for col in row.iter() {
                let chr = if *col { "x" } else { " " };
                try!(write!(formatter, "{}│", chr));
            }
            try!(formatter.write_str("\n"));

            // Print box border between rows
            if i != NUM_ROWS - 1 {
                try!(formatter.write_str("    ├─"));
                for _ in 0..NUM_COLS - 1 {
                    try!(formatter.write_str("┼─"));
                }
                try!(formatter.write_str("┤\n"));
            }
        }

        // Print bottom box border
        try!(formatter.write_str("    └─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┴─"));
        }
        try!(formatter.write_str("┘\n"));

        write!(formatter, "{:?}", self.board_type)
    }
}
<|endoftext|>


<commit_before>use chrono;

use super::duration::{FloatDuration, TimePoint};

pub struct GameTime {
    wall_time_elapsed: FloatDuration,
    game_time_elapsed: FloatDuration,
    game_time_total: FloatDuration,
    frame_number: u64,
}

pub struct GameClock {
    wall_start_global: chrono::DateTime<chrono::Local>,
    wall_start_frame: chrono::DateTime<chrono::Local>,
    game_start_frame: FloatDuration,
    game_time_elapsed: FloatDuration,
    wall_time_elapsed: FloatDuration,
    current_frame: u64,
    clock_multiplier: f64,
}

impl GameClock {
    pub fn new() -> GameClock {
        GameClock {
            wall_start_global: chrono::Local::now(),
            wall_start_frame: chrono::Local::now(),
            game_start_frame: FloatDuration::milliseconds(0.0),
            game_time_elapsed: FloatDuration::milliseconds(0.0),
            wall_time_elapsed: FloatDuration::milliseconds(0.0),
            current_frame: 0,
            clock_multiplier: 1.0,
        }
    }

    pub fn current_frame(&self) -> u64 {
        self.current_frame
    }
    pub fn game_start_time(&self) -> chrono::DateTime<chrono::Local> {
        self.wall_start_global
    }
    pub fn clock_multiplier(&self) -> f64 {
        self.clock_multiplier
    }
    pub fn set_clock_multiplier(&mut self, val: f64) -> &mut GameClock {
        self.clock_multiplier = val;
        self
    }

    pub fn tick(&mut self) -> GameTime {
        let now = chrono::Local::now();

        let time_elapsed = now.float_duration_since(self.wall_start_frame).unwrap();
        let game_time_elapsed = time_elapsed * self.clock_multiplier;
        let cur_game_time = self.game_start_frame + game_time_elapsed;
        let current_frame = self.current_frame;

        self.current_frame += 1;
        self.game_time_elapsed = game_time_elapsed;
        self.wall_time_elapsed = time_elapsed;
        self.game_start_frame = cur_game_time;
        self.wall_start_frame = now;

        GameTime {
            wall_time_elapsed: time_elapsed,
            game_time_elapsed,
            game_time_total: cur_game_time,
            frame_number: current_frame,
        }
    }
}

impl GameTime {
}

<commit_msg>Upgrades to GameTime and GameClock.<commit_after>use chrono;

use super::duration::{FloatDuration, TimePoint};

pub struct GameTime {
    wall_time_elapsed: FloatDuration,
    game_time_elapsed: FloatDuration,
    game_time_total: FloatDuration,
    frame_number: u64,
}

pub struct GameClock {
    wall_start_global: chrono::DateTime<chrono::Local>,
    wall_start_frame: chrono::DateTime<chrono::Local>,
    game_start_frame: FloatDuration,
    game_time_elapsed: FloatDuration,
    wall_time_elapsed: FloatDuration,
    current_frame: u64,
    clock_multiplier: f64,
}

impl GameClock {
    pub fn new() -> GameClock {
        GameClock {
            wall_start_global: chrono::Local::now(),
            wall_start_frame: chrono::Local::now(),
            game_start_frame: FloatDuration::milliseconds(0.0),
            game_time_elapsed: FloatDuration::milliseconds(0.0),
            wall_time_elapsed: FloatDuration::milliseconds(0.0),
            current_frame: 0,
            clock_multiplier: 1.0,
        }
    }

    pub fn current_frame(&self) -> u64 {
        self.current_frame
    }
    pub fn game_start_time(&self) -> chrono::DateTime<chrono::Local> {
        self.wall_start_global
    }
    pub fn last_frame_game_time(&self) -> FloatDuration {
        self.game_start_frame
    }
    pub fn last_frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.wall_start_frame
    }
    pub fn frame_elapsed_time(&self) -> FloatDuration {
        chrono::Local::now().float_duration_since(self.wall_start_frame).unwrap()
    }

    pub fn clock_multiplier(&self) -> f64 {
        self.clock_multiplier
    }
    pub fn set_clock_multiplier(&mut self, val: f64) -> &mut GameClock {
        self.clock_multiplier = val;
        self
    }

    pub fn tick(&mut self) -> GameTime {
        let now = chrono::Local::now();

        let time_elapsed = now.float_duration_since(self.wall_start_frame).unwrap();
        let game_time_elapsed = time_elapsed * self.clock_multiplier;
        let cur_game_time = self.game_start_frame + game_time_elapsed;
        let current_frame = self.current_frame;

        self.current_frame += 1;
        self.game_time_elapsed = game_time_elapsed;
        self.wall_time_elapsed = time_elapsed;
        self.game_start_frame = cur_game_time;
        self.wall_start_frame = now;

        GameTime {
            wall_time_elapsed: time_elapsed,
            game_time_elapsed,
            game_time_total: cur_game_time,
            frame_number: current_frame,
        }
    }
}

impl GameTime {
    pub fn elapsed_wall_time(&self) -> FloatDuration {
        self.wall_time_elapsed
    }
    pub fn elapsed_game_time(&self) -> FloatDuration {
        self.game_time_elapsed
    }
    pub fn total_game_time(&self) -> FloatDuration {
        self.game_time_total
    }
    pub fn frame_number(&self) -> u64 {
        self.frame_number
    }
}

<|endoftext|>


<commit_before>mod instructions_template;
mod static_string_indexing;

use instructions_template::generate_instructions_rs;
use static_string_indexing::index_static_strings;

use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::{self, Command, Stdio};

fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
    let entries = match current_dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return,
    };

    for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
        if entry.is_dir() {
            if let Some(file_name) = entry.file_name() {
                let new_prefix = prefix.to_owned() + file_name.to_str().unwrap() + "/";
                find_prolog_files(libraries, &new_prefix, &entry);
            }
        } else if entry.is_file() {
            let ext = std::ffi::OsStr::new("pl");
            if entry.extension() == Some(ext) {
                let contain = String::from_utf8(fs::read(&entry).unwrap()).unwrap();
                let name = entry.file_stem().unwrap().to_str().unwrap();

                let line = format!(
                    "        m.insert(\"{}\",\n{:?});\n",
                    prefix.to_owned() + name,
                    contain
                );

                libraries.write_all(line.as_bytes()).unwrap();
            }
        }
    }
}

fn main() {
    let has_rustfmt = Command::new("rustfmt")
        .arg("--version")
        .stdin(Stdio::inherit())
        .status()
        .is_ok();

    if !has_rustfmt {
        println!("Failed to run rustfmt, will skip formatting generated files.")
    }

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("libraries.rs");

    let mut libraries = File::create(&dest_path).unwrap();
    let lib_path = Path::new("src/lib");

    libraries
        .write_all(
            b"ref_thread_local::ref_thread_local! {
    pub(crate) static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
        let mut m = IndexMap::new();\n",
        )
        .unwrap();

    find_prolog_files(&mut libraries, "", &lib_path);
    libraries.write_all(b"\n        m\n    };\n}\n").unwrap();

    let instructions_path = Path::new(&out_dir).join("instructions.rs");
    let mut instructions_file = File::create(&instructions_path).unwrap();

    let quoted_output = generate_instructions_rs();

    instructions_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    if has_rustfmt {
        format_generated_file(instructions_path.as_path());
    }

    let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
    let mut static_atoms_file = File::create(&static_atoms_path).unwrap();

    let quoted_output = index_static_strings(&instructions_path);

    static_atoms_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    if has_rustfmt {
        format_generated_file(static_atoms_path.as_path());
    }

    println!("cargo:rerun-if-changed=src/");
}

fn format_generated_file(path: &Path) {
    Command::new("rustfmt")
        .arg(path.as_os_str())
        .spawn()
        .unwrap_or_else(|err| {
            eprintln!(
                "{}: rustfmt (https://github.com/rust-lang/rustfmt) \
                is required build time dependency and must be available \
                in the environment's PATH variable.",
                err
            );
            process::exit(1);
        })
        .wait()
        .unwrap();
}
<commit_msg>adjust error message on failed formatting<commit_after>mod instructions_template;
mod static_string_indexing;

use instructions_template::generate_instructions_rs;
use static_string_indexing::index_static_strings;

use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::{Command, Stdio};

fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
    let entries = match current_dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return,
    };

    for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
        if entry.is_dir() {
            if let Some(file_name) = entry.file_name() {
                let new_prefix = prefix.to_owned() + file_name.to_str().unwrap() + "/";
                find_prolog_files(libraries, &new_prefix, &entry);
            }
        } else if entry.is_file() {
            let ext = std::ffi::OsStr::new("pl");
            if entry.extension() == Some(ext) {
                let contain = String::from_utf8(fs::read(&entry).unwrap()).unwrap();
                let name = entry.file_stem().unwrap().to_str().unwrap();

                let line = format!(
                    "        m.insert(\"{}\",\n{:?});\n",
                    prefix.to_owned() + name,
                    contain
                );

                libraries.write_all(line.as_bytes()).unwrap();
            }
        }
    }
}

fn main() {
    let has_rustfmt = Command::new("rustfmt")
        .arg("--version")
        .stdin(Stdio::inherit())
        .status()
        .is_ok();

    if !has_rustfmt {
        println!("Failed to run rustfmt, will skip formatting generated files.")
    }

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("libraries.rs");

    let mut libraries = File::create(&dest_path).unwrap();
    let lib_path = Path::new("src/lib");

    libraries
        .write_all(
            b"ref_thread_local::ref_thread_local! {
    pub(crate) static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
        let mut m = IndexMap::new();\n",
        )
        .unwrap();

    find_prolog_files(&mut libraries, "", &lib_path);
    libraries.write_all(b"\n        m\n    };\n}\n").unwrap();

    let instructions_path = Path::new(&out_dir).join("instructions.rs");
    let mut instructions_file = File::create(&instructions_path).unwrap();

    let quoted_output = generate_instructions_rs();

    instructions_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    if has_rustfmt {
        format_generated_file(instructions_path.as_path());
    }

    let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
    let mut static_atoms_file = File::create(&static_atoms_path).unwrap();

    let quoted_output = index_static_strings(&instructions_path);

    static_atoms_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    if has_rustfmt {
        format_generated_file(static_atoms_path.as_path());
    }

    println!("cargo:rerun-if-changed=src/");
}

fn format_generated_file(path: &Path) {
    Command::new("rustfmt")
        .arg(path.as_os_str())
        .spawn()
        .unwrap_or_else(|err| {
            panic!(
                "{}: rustfmt was detected as available, but failed to format generated file '{}'",
                err,
                path.display()
            );
        })
        .wait()
        .unwrap();
}
<|endoftext|>


<commit_before>//! Delays
//!
//! # Implementation details
//!
//! This module uses the TIM7 peripheral and the `_tim7` interrupt under the hood.

use cortex_m::{self, asm};
use peripheral;

/// Blocks for `n` ms
pub fn ms(n: u16) {
    #[allow(dead_code)]
    #[export_name = "_tim7"]
    #[linkage = "weak"]
    pub unsafe extern "C" fn interrupt_handler() {
        // Clear the update flag
        peripheral::tim7_mut().sr.write(|w| w);
    }

    unsafe {
        let tim7 = peripheral::tim7_mut();

        // The alarm (the "update event") will set off in `n` "ticks".
        // One tick = 1 ms (see `init`)
        tim7.arr.write(|w| w.arr(n));

        // Trigger an "update" to reload the auto reload register
        tim7.egr.write(|w| w.ug(true));

        // CEN: Enable the counter
        tim7.cr1.modify(|_, w| w.cen(true));

        // XXX this assumes that `_tim7` is the only interrupt that can occur.
        asm::wfi();
    }
}

/// Initializes the necessary stuff to be able to use delays
///
/// # Safety
///
/// - Must be called once
/// - Must be called in an interrupt-free environment
pub unsafe fn init() {
    let nvic = cortex_m::peripheral::nvic_mut();
    let rcc = peripheral::rcc_mut();
    let tim7 = peripheral::tim7_mut();

    // RCC: Enable TIM7
    rcc.apb1enr.modify(|_, w| w.tim7en(true));

    // CEN: Disable the clock
    // OPM. Enable One Pulse Mode. Stop the counter after the next update event.
    tim7.cr1.write(|w| w.cen(false).opm(true));

    // Enable "update" interrupts
    tim7.dier.write(|w| w.uie(true));

    // NVIC: Unmask the interrupt (N = 55)
    nvic.iser[1].write(1 << (55 - 32));

    // Set pre-scaler to 8_000 -> Frequency = 1 KHz
    tim7.psc.write(|w| w.psc(7_999));
}
<commit_msg>delay::ms: switch back to busy waiting<commit_after>//! Delays
//!
//! # Implementation details
//!
//! This module uses the TIM7 peripheral and the `_tim7` interrupt under the hood.

use peripheral;

/// Blocks for `n` ms
pub fn ms(n: u16) {
    unsafe {
        let tim7 = peripheral::tim7_mut();

        // The alarm (the "update event") will set off in `n` "ticks".
        // One tick = 1 ms (see `init`)
        tim7.arr.write(|w| w.arr(n));

        // CEN: Enable the counter
        tim7.cr1.modify(|_, w| w.cen(true));

        // Wait until the alarm goes off (the "update event" occurs)
        while !tim7.sr.read().uif() {}

        // Clear the "update" flag
        tim7.sr.write(|w| w);
    }
}

/// Initializes the necessary stuff to be able to use delays
///
/// # Safety
///
/// - Must be called once
/// - Must be called in an interrupt-free environment
pub unsafe fn init() {
    let rcc = peripheral::rcc_mut();
    let tim7 = peripheral::tim7_mut();

    // RCC: Enable TIM7
    rcc.apb1enr.modify(|_, w| w.tim7en(true));

    // CEN: Disable the clock
    // OPM. Enable One Pulse Mode. Stop the counter after the next update event.
    tim7.cr1.write(|w| w.cen(false).opm(true));

    // Set pre-scaler to 8_000 -> Frequency = 1 KHz
    tim7.psc.write(|w| w.psc(7_999));
}
<|endoftext|>


<commit_before>use abra::schema::{FieldRef, SchemaRead};
use abra::query::Query;
use abra::collectors::Collector;

use super::{RocksDBIndexReader, TermRef};

#[derive(Debug, Clone)]
enum BooleanQueryOp {
    Zero,
    One,
    Load(FieldRef, TermRef),
    And,
    Or,
    AndNot,
}

struct SearchPlan {
    boolean_query: Vec<BooleanQueryOp>,
}

impl<'a> RocksDBIndexReader<'a> {
    fn plan_boolean_query_combinator(&self, mut boolean_query: &mut Vec<BooleanQueryOp>, queries: &Vec<Query>, join_op: BooleanQueryOp) {
        match queries.len() {
            0 => boolean_query.push(BooleanQueryOp::Zero),
            1 => {
                self.plan_boolean_query(&mut boolean_query, &queries[0]);
            }
            _ => {
                // TODO: organise queries into a binary tree structure

                let mut query_iter = queries.iter();
                self.plan_boolean_query(&mut boolean_query, query_iter.next().unwrap());

                for query in query_iter {
                    self.plan_boolean_query(&mut boolean_query, query);
                    boolean_query.push(join_op.clone());
                }
            }
        }
    }

    fn plan_boolean_query(&self, mut boolean_query: &mut Vec<BooleanQueryOp>, query: &Query) {
        match *query {
            Query::MatchAll{ref score} => {
                boolean_query.push(BooleanQueryOp::One);
            },
            Query::MatchNone => {
                boolean_query.push(BooleanQueryOp::Zero);
            },
            Query::MatchTerm{ref field, ref term, ref matcher, ref scorer} => {
                // Get term
                let term_bytes = term.to_bytes();
                let term_ref = match self.store.term_dictionary.read().unwrap().get(&term_bytes) {
                    Some(term_ref) => *term_ref,
                    None => {
                        // Term doesn't exist, so will never match
                        boolean_query.push(BooleanQueryOp::Zero);
                        return
                    }
                };

                // Get field
                let field_ref = match self.schema().get_field_by_name(field) {
                    Some(field_ref) => field_ref,
                    None => {
                        // Field doesn't exist, so will never match
                        boolean_query.push(BooleanQueryOp::Zero);
                        return
                    }
                };

                boolean_query.push(BooleanQueryOp::Load(field_ref, term_ref));
            }
            Query::Conjunction{ref queries} => {
                self.plan_boolean_query_combinator(&mut boolean_query, queries, BooleanQueryOp::And);
            }
            Query::Disjunction{ref queries} => {
                self.plan_boolean_query_combinator(&mut boolean_query, queries, BooleanQueryOp::Or);
            }
            Query::NDisjunction{ref queries, minimum_should_match} => {
                self.plan_boolean_query_combinator(&mut boolean_query, queries, BooleanQueryOp::Or);
            }
            Query::DisjunctionMax{ref queries} => {
                self.plan_boolean_query_combinator(&mut boolean_query, queries, BooleanQueryOp::Or);
            }
            Query::Filter{ref query, ref filter} => {
                self.plan_boolean_query(&mut boolean_query, query);
                self.plan_boolean_query(&mut boolean_query, filter);
                boolean_query.push(BooleanQueryOp::And);
            }
            Query::Exclude{ref query, ref exclude} => {
                self.plan_boolean_query(&mut boolean_query, query);
                self.plan_boolean_query(&mut boolean_query, exclude);
                boolean_query.push(BooleanQueryOp::AndNot);
            }
        }
    }

    pub fn search<C: Collector>(&self, collector: &mut C, query: &Query) {
        let mut boolean_query = Vec::new();
        self.plan_boolean_query(&mut boolean_query, query);
        println!("BQ {:?}", boolean_query);

        let plan = SearchPlan {
            boolean_query: boolean_query,
        };
    }
}<commit_msg>Cleanup in query planner<commit_after>use abra::schema::{FieldRef, SchemaRead};
use abra::query::Query;
use abra::collectors::Collector;

use super::{RocksDBIndexReader, TermRef};

#[derive(Debug, Clone)]
enum BooleanQueryOp {
    Zero,
    One,
    Load(FieldRef, TermRef),
    And,
    Or,
    AndNot,
}

#[derive(Debug)]
struct SearchPlan {
    boolean_query: Vec<BooleanQueryOp>,
}

impl SearchPlan {
    fn new() -> SearchPlan {
        SearchPlan {
            boolean_query: Vec::new(),
        }
    }
}

impl<'a> RocksDBIndexReader<'a> {
    fn plan_query_combinator(&self, mut plan: &mut SearchPlan, queries: &Vec<Query>, join_op: BooleanQueryOp) {
        match queries.len() {
            0 => plan.boolean_query.push(BooleanQueryOp::Zero),
            1 => {
                self.plan_query(&mut plan, &queries[0]);
            }
            _ => {
                // TODO: organise queries into a binary tree structure

                let mut query_iter = queries.iter();
                self.plan_query(&mut plan, query_iter.next().unwrap());

                for query in query_iter {
                    self.plan_query(&mut plan, query);
                    plan.boolean_query.push(join_op.clone());
                }
            }
        }
    }

    fn plan_query(&self, mut plan: &mut SearchPlan, query: &Query) {
        match *query {
            Query::MatchAll{ref score} => {
                plan.boolean_query.push(BooleanQueryOp::One);
            }
            Query::MatchNone => {
                plan.boolean_query.push(BooleanQueryOp::Zero);
            }
            Query::MatchTerm{ref field, ref term, ref matcher, ref scorer} => {
                // Get term
                let term_bytes = term.to_bytes();
                let term_ref = match self.store.term_dictionary.read().unwrap().get(&term_bytes) {
                    Some(term_ref) => *term_ref,
                    None => {
                        // Term doesn't exist, so will never match
                        plan.boolean_query.push(BooleanQueryOp::Zero);
                        return
                    }
                };

                // Get field
                let field_ref = match self.schema().get_field_by_name(field) {
                    Some(field_ref) => field_ref,
                    None => {
                        // Field doesn't exist, so will never match
                        plan.boolean_query.push(BooleanQueryOp::Zero);
                        return
                    }
                };

                plan.boolean_query.push(BooleanQueryOp::Load(field_ref, term_ref));
            }
            Query::Conjunction{ref queries} => {
                self.plan_query_combinator(&mut plan, queries, BooleanQueryOp::And);
            }
            Query::Disjunction{ref queries} => {
                self.plan_query_combinator(&mut plan, queries, BooleanQueryOp::Or);
            }
            Query::NDisjunction{ref queries, minimum_should_match} => {
                self.plan_query_combinator(&mut plan, queries, BooleanQueryOp::Or);
            }
            Query::DisjunctionMax{ref queries} => {
                self.plan_query_combinator(&mut plan, queries, BooleanQueryOp::Or);
            }
            Query::Filter{ref query, ref filter} => {
                self.plan_query(&mut plan, query);
                self.plan_query(&mut plan, filter);
                plan.boolean_query.push(BooleanQueryOp::And);
            }
            Query::Exclude{ref query, ref exclude} => {
                self.plan_query(&mut plan, query);
                self.plan_query(&mut plan, exclude);
                plan.boolean_query.push(BooleanQueryOp::AndNot);
            }
        }
    }

    pub fn search<C: Collector>(&self, collector: &mut C, query: &Query) {
        let mut plan = SearchPlan::new();
        self.plan_query(&mut plan, query);
        println!("Plan {:?}", plan);
    }
}<|endoftext|>


<commit_before>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io;

use httparse;
use http;

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

type Cause = Box<StdError + Send + Sync>;

/// Represents errors that can occur handling HTTP streams.
pub struct Error {
    inner: Box<ErrorImpl>,
}

struct ErrorImpl {
    kind: Kind,
    cause: Option<Cause>,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Kind {
    Parse(Parse),
    /// A message reached EOF, but is not complete.
    Incomplete,
    /// A client connection received a response when not waiting for one.
    MismatchedResponse,
    /// A pending item was dropped before ever being processed.
    Canceled,
    /// Indicates a connection is closed.
    Closed,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io,
    /// Error occurred while connecting.
    Connect,
    /// Error creating a TcpListener.
    #[cfg(feature = "runtime")]
    Listen,
    /// Error accepting on an Incoming stream.
    Accept,
    /// Error calling user's NewService::new_service().
    NewService,
    /// Error from future of user's Service::call().
    Service,
    /// Error while reading a body from connection.
    Body,
    /// Error while writing a body to connection.
    BodyWrite,
    /// Error calling user's Payload::poll_data().
    BodyUser,
    /// Error calling AsyncWrite::shutdown()
    Shutdown,

    /// A general error from h2.
    Http2,

    /// User tried to create a Request with bad version.
    UnsupportedVersion,
    /// User tried to create a CONNECT Request with the Client.
    UnsupportedRequestMethod,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Parse {
    Method,
    Version,
    VersionH2,
    Uri,
    Header,
    TooLarge,
    Status,

    /// A protocol upgrade was encountered, but not yet supported in hyper.
    UpgradeNotSupported,
}

/*
#[derive(Debug)]
pub(crate) enum User {
    VersionNotSupported,
    MethodNotSupported,
    InvalidRequestUri,
}
*/

impl Error {
    //TODO(error): should there be these kinds of inspection methods?
    //
    // - is_io()
    // - is_connect()
    // - is_closed()
    // - etc?

    /// Returns true if this was an HTTP parse error.
    pub fn is_parse(&self) -> bool {
        match self.inner.kind {
            Kind::Parse(_) => true,
            _ => false,
        }
    }

    /// Returns true if this error was caused by user code.
    pub fn is_user(&self) -> bool {
        match self.inner.kind {
            Kind::BodyUser |
            Kind::NewService |
            Kind::Service |
            Kind::Closed |
            Kind::UnsupportedVersion |
            Kind::UnsupportedRequestMethod => true,
            _ => false,
        }
    }

    /// Returns true if this was about a `Request` that was canceled.
    pub fn is_canceled(&self) -> bool {
        self.inner.kind == Kind::Canceled
    }

    /// Returns true if a sender's channel is closed.
    pub fn is_closed(&self) -> bool {
        self.inner.kind == Kind::Closed
    }

    pub(crate) fn new(kind: Kind, cause: Option<Cause>) -> Error {
        Error {
            inner: Box::new(ErrorImpl {
                kind,
                cause,
            }),
        }
    }

    pub(crate) fn kind(&self) -> &Kind {
        &self.inner.kind
    }

    pub(crate) fn new_canceled<E: Into<Cause>>(cause: Option<E>) -> Error {
        Error::new(Kind::Canceled, cause.map(Into::into))
    }

    pub(crate) fn new_incomplete() -> Error {
        Error::new(Kind::Incomplete, None)
    }

    pub(crate) fn new_too_large() -> Error {
        Error::new(Kind::Parse(Parse::TooLarge), None)
    }

    pub(crate) fn new_header() -> Error {
        Error::new(Kind::Parse(Parse::Header), None)
    }

    pub(crate) fn new_status() -> Error {
        Error::new(Kind::Parse(Parse::Status), None)
    }

    pub(crate) fn new_version_h2() -> Error {
        Error::new(Kind::Parse(Parse::VersionH2), None)
    }

    pub(crate) fn new_mismatched_response() -> Error {
        Error::new(Kind::MismatchedResponse, None)
    }

    pub(crate) fn new_io(cause: io::Error) -> Error {
        Error::new(Kind::Io, Some(cause.into()))
    }

    #[cfg(feature = "runtime")]
    pub(crate) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Listen, Some(cause.into()))
    }

    pub(crate) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Accept, Some(cause.into()))
    }

    pub(crate) fn new_connect<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Connect, Some(cause.into()))
    }

    pub(crate) fn new_closed() -> Error {
        Error::new(Kind::Closed, None)
    }

    pub(crate) fn new_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Body, Some(cause.into()))
    }

    pub(crate) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::BodyWrite, Some(cause.into()))
    }

    pub(crate) fn new_user_unsupported_version() -> Error {
        Error::new(Kind::UnsupportedVersion, None)
    }

    pub(crate) fn new_user_unsupported_request_method() -> Error {
        Error::new(Kind::UnsupportedRequestMethod, None)
    }

    pub(crate) fn new_user_new_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::NewService, Some(cause.into()))
    }

    pub(crate) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Service, Some(cause.into()))
    }

    pub(crate) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::BodyUser, Some(cause.into()))
    }

    pub(crate) fn new_shutdown(cause: io::Error) -> Error {
        Error::new(Kind::Shutdown, Some(Box::new(cause)))
    }

    pub(crate) fn new_h2(cause: ::h2::Error) -> Error {
        Error::new(Kind::Http2, Some(Box::new(cause)))
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Error")
            .field("kind", &self.inner.kind)
            .field("cause", &self.inner.cause)
            .finish()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref cause) = self.inner.cause {
            write!(f, "{}: {}", self.description(), cause)
        } else {
            f.write_str(self.description())
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.inner.kind {
            Kind::Parse(Parse::Method) => "invalid Method specified",
            Kind::Parse(Parse::Version) => "invalid HTTP version specified",
            Kind::Parse(Parse::VersionH2) => "invalid HTTP version specified (Http2)",
            Kind::Parse(Parse::Uri) => "invalid URI",
            Kind::Parse(Parse::Header) => "invalid Header provided",
            Kind::Parse(Parse::TooLarge) => "message head is too large",
            Kind::Parse(Parse::Status) => "invalid Status provided",
            Kind::Parse(Parse::UpgradeNotSupported) => "unsupported protocol upgrade",
            Kind::Incomplete => "message is incomplete",
            Kind::MismatchedResponse => "response received without matching request",
            Kind::Closed => "connection closed",
            Kind::Connect => "an error occurred trying to connect",
            Kind::Canceled => "an operation was canceled internally before starting",
            #[cfg(feature = "runtime")]
            Kind::Listen => "error creating server listener",
            Kind::Accept => "error accepting connection",
            Kind::NewService => "calling user's new_service failed",
            Kind::Service => "error from user's server service",
            Kind::Body => "error reading a body from connection",
            Kind::BodyWrite => "error writing a body to connection",
            Kind::BodyUser => "error from user's Payload stream",
            Kind::Shutdown => "error shutting down connection",
            Kind::Http2 => "http2 general error",
            Kind::UnsupportedVersion => "request has unsupported HTTP version",
            Kind::UnsupportedRequestMethod => "request has unsupported HTTP method",

            Kind::Io => "an IO error occurred",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        self
            .inner
            .cause
            .as_ref()
            .map(|cause| &**cause as &StdError)
    }
}

#[doc(hidden)]
impl From<Parse> for Error {
    fn from(err: Parse) -> Error {
        Error::new(Kind::Parse(err), None)
    }
}

impl From<httparse::Error> for Parse {
    fn from(err: httparse::Error) -> Parse {
        match err {
            httparse::Error::HeaderName |
            httparse::Error::HeaderValue |
            httparse::Error::NewLine |
            httparse::Error::Token => Parse::Header,
            httparse::Error::Status => Parse::Status,
            httparse::Error::TooManyHeaders => Parse::TooLarge,
            httparse::Error::Version => Parse::Version,
        }
    }
}

impl From<http::method::InvalidMethod> for Parse {
    fn from(_: http::method::InvalidMethod) -> Parse {
        Parse::Method
    }
}

impl From<http::status::InvalidStatusCode> for Parse {
    fn from(_: http::status::InvalidStatusCode) -> Parse {
        Parse::Status
    }
}

impl From<http::uri::InvalidUri> for Parse {
    fn from(_: http::uri::InvalidUri) -> Parse {
        Parse::Uri
    }
}

#[doc(hidden)]
trait AssertSendSync: Send + Sync + 'static {}
#[doc(hidden)]
impl AssertSendSync for Error {}

#[cfg(test)]
mod tests {
}
<commit_msg>feat(error): add `Error::cause2` and `Error::into_cause`<commit_after>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io;

use httparse;
use http;

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

type Cause = Box<StdError + Send + Sync>;

/// Represents errors that can occur handling HTTP streams.
pub struct Error {
    inner: Box<ErrorImpl>,
}

struct ErrorImpl {
    kind: Kind,
    cause: Option<Cause>,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Kind {
    Parse(Parse),
    /// A message reached EOF, but is not complete.
    Incomplete,
    /// A client connection received a response when not waiting for one.
    MismatchedResponse,
    /// A pending item was dropped before ever being processed.
    Canceled,
    /// Indicates a connection is closed.
    Closed,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io,
    /// Error occurred while connecting.
    Connect,
    /// Error creating a TcpListener.
    #[cfg(feature = "runtime")]
    Listen,
    /// Error accepting on an Incoming stream.
    Accept,
    /// Error calling user's NewService::new_service().
    NewService,
    /// Error from future of user's Service::call().
    Service,
    /// Error while reading a body from connection.
    Body,
    /// Error while writing a body to connection.
    BodyWrite,
    /// Error calling user's Payload::poll_data().
    BodyUser,
    /// Error calling AsyncWrite::shutdown()
    Shutdown,

    /// A general error from h2.
    Http2,

    /// User tried to create a Request with bad version.
    UnsupportedVersion,
    /// User tried to create a CONNECT Request with the Client.
    UnsupportedRequestMethod,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Parse {
    Method,
    Version,
    VersionH2,
    Uri,
    Header,
    TooLarge,
    Status,

    /// A protocol upgrade was encountered, but not yet supported in hyper.
    UpgradeNotSupported,
}

/*
#[derive(Debug)]
pub(crate) enum User {
    VersionNotSupported,
    MethodNotSupported,
    InvalidRequestUri,
}
*/

impl Error {
    //TODO(error): should there be these kinds of inspection methods?
    //
    // - is_io()
    // - is_connect()
    // - is_closed()
    // - etc?

    /// Returns true if this was an HTTP parse error.
    pub fn is_parse(&self) -> bool {
        match self.inner.kind {
            Kind::Parse(_) => true,
            _ => false,
        }
    }

    /// Returns true if this error was caused by user code.
    pub fn is_user(&self) -> bool {
        match self.inner.kind {
            Kind::BodyUser |
            Kind::NewService |
            Kind::Service |
            Kind::Closed |
            Kind::UnsupportedVersion |
            Kind::UnsupportedRequestMethod => true,
            _ => false,
        }
    }

    /// Returns true if this was about a `Request` that was canceled.
    pub fn is_canceled(&self) -> bool {
        self.inner.kind == Kind::Canceled
    }

    /// Returns true if a sender's channel is closed.
    pub fn is_closed(&self) -> bool {
        self.inner.kind == Kind::Closed
    }

    /// Returns the error's cause.
    ///
    /// This is identical to `Error::cause` except that it provides extra
    /// bounds required to be able to downcast the error.
    pub fn cause2(&self) -> Option<&(StdError + 'static + Sync + Send)> {
        self.inner.cause.as_ref().map(|e| &**e)
    }

    /// Consumes the error, returning its cause.
    pub fn into_cause(self) -> Option<Box<StdError + Sync + Send>> {
        self.inner.cause
    }

    pub(crate) fn new(kind: Kind, cause: Option<Cause>) -> Error {
        Error {
            inner: Box::new(ErrorImpl {
                kind,
                cause,
            }),
        }
    }

    pub(crate) fn kind(&self) -> &Kind {
        &self.inner.kind
    }

    pub(crate) fn new_canceled<E: Into<Cause>>(cause: Option<E>) -> Error {
        Error::new(Kind::Canceled, cause.map(Into::into))
    }

    pub(crate) fn new_incomplete() -> Error {
        Error::new(Kind::Incomplete, None)
    }

    pub(crate) fn new_too_large() -> Error {
        Error::new(Kind::Parse(Parse::TooLarge), None)
    }

    pub(crate) fn new_header() -> Error {
        Error::new(Kind::Parse(Parse::Header), None)
    }

    pub(crate) fn new_status() -> Error {
        Error::new(Kind::Parse(Parse::Status), None)
    }

    pub(crate) fn new_version_h2() -> Error {
        Error::new(Kind::Parse(Parse::VersionH2), None)
    }

    pub(crate) fn new_mismatched_response() -> Error {
        Error::new(Kind::MismatchedResponse, None)
    }

    pub(crate) fn new_io(cause: io::Error) -> Error {
        Error::new(Kind::Io, Some(cause.into()))
    }

    #[cfg(feature = "runtime")]
    pub(crate) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Listen, Some(cause.into()))
    }

    pub(crate) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Accept, Some(cause.into()))
    }

    pub(crate) fn new_connect<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Connect, Some(cause.into()))
    }

    pub(crate) fn new_closed() -> Error {
        Error::new(Kind::Closed, None)
    }

    pub(crate) fn new_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Body, Some(cause.into()))
    }

    pub(crate) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::BodyWrite, Some(cause.into()))
    }

    pub(crate) fn new_user_unsupported_version() -> Error {
        Error::new(Kind::UnsupportedVersion, None)
    }

    pub(crate) fn new_user_unsupported_request_method() -> Error {
        Error::new(Kind::UnsupportedRequestMethod, None)
    }

    pub(crate) fn new_user_new_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::NewService, Some(cause.into()))
    }

    pub(crate) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Service, Some(cause.into()))
    }

    pub(crate) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::BodyUser, Some(cause.into()))
    }

    pub(crate) fn new_shutdown(cause: io::Error) -> Error {
        Error::new(Kind::Shutdown, Some(Box::new(cause)))
    }

    pub(crate) fn new_h2(cause: ::h2::Error) -> Error {
        Error::new(Kind::Http2, Some(Box::new(cause)))
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Error")
            .field("kind", &self.inner.kind)
            .field("cause", &self.inner.cause)
            .finish()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref cause) = self.inner.cause {
            write!(f, "{}: {}", self.description(), cause)
        } else {
            f.write_str(self.description())
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.inner.kind {
            Kind::Parse(Parse::Method) => "invalid Method specified",
            Kind::Parse(Parse::Version) => "invalid HTTP version specified",
            Kind::Parse(Parse::VersionH2) => "invalid HTTP version specified (Http2)",
            Kind::Parse(Parse::Uri) => "invalid URI",
            Kind::Parse(Parse::Header) => "invalid Header provided",
            Kind::Parse(Parse::TooLarge) => "message head is too large",
            Kind::Parse(Parse::Status) => "invalid Status provided",
            Kind::Parse(Parse::UpgradeNotSupported) => "unsupported protocol upgrade",
            Kind::Incomplete => "message is incomplete",
            Kind::MismatchedResponse => "response received without matching request",
            Kind::Closed => "connection closed",
            Kind::Connect => "an error occurred trying to connect",
            Kind::Canceled => "an operation was canceled internally before starting",
            #[cfg(feature = "runtime")]
            Kind::Listen => "error creating server listener",
            Kind::Accept => "error accepting connection",
            Kind::NewService => "calling user's new_service failed",
            Kind::Service => "error from user's server service",
            Kind::Body => "error reading a body from connection",
            Kind::BodyWrite => "error writing a body to connection",
            Kind::BodyUser => "error from user's Payload stream",
            Kind::Shutdown => "error shutting down connection",
            Kind::Http2 => "http2 general error",
            Kind::UnsupportedVersion => "request has unsupported HTTP version",
            Kind::UnsupportedRequestMethod => "request has unsupported HTTP method",

            Kind::Io => "an IO error occurred",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        self
            .inner
            .cause
            .as_ref()
            .map(|cause| &**cause as &StdError)
    }
}

#[doc(hidden)]
impl From<Parse> for Error {
    fn from(err: Parse) -> Error {
        Error::new(Kind::Parse(err), None)
    }
}

impl From<httparse::Error> for Parse {
    fn from(err: httparse::Error) -> Parse {
        match err {
            httparse::Error::HeaderName |
            httparse::Error::HeaderValue |
            httparse::Error::NewLine |
            httparse::Error::Token => Parse::Header,
            httparse::Error::Status => Parse::Status,
            httparse::Error::TooManyHeaders => Parse::TooLarge,
            httparse::Error::Version => Parse::Version,
        }
    }
}

impl From<http::method::InvalidMethod> for Parse {
    fn from(_: http::method::InvalidMethod) -> Parse {
        Parse::Method
    }
}

impl From<http::status::InvalidStatusCode> for Parse {
    fn from(_: http::status::InvalidStatusCode) -> Parse {
        Parse::Status
    }
}

impl From<http::uri::InvalidUri> for Parse {
    fn from(_: http::uri::InvalidUri) -> Parse {
        Parse::Uri
    }
}

#[doc(hidden)]
trait AssertSendSync: Send + Sync + 'static {}
#[doc(hidden)]
impl AssertSendSync for Error {}

#[cfg(test)]
mod tests {
}
<|endoftext|>


<commit_before>//! `std:error:Error` implementations

use std::fmt;
use std::io;
use std::error::{Error, FromError};

/// `Error` variants for public errors in this crate
pub enum Chip8Error {
    /// I/O error
    Io(&'static str, Option<io::Error>),
}

impl fmt::Display for Chip8Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        return write!(fmt, "{}", self.description())
    }
}

impl Error for Chip8Error {
    fn description(&self) -> &str {
        match *self {
            Chip8Error::Io(desc, _) => desc,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            Chip8Error::Io(_, Some(ref cause)) => Some(cause),
            _ => None,
        }
    }
}

impl FromError<io::Error> for Chip8Error {
    fn from_error(err: io::Error) -> Chip8Error {
        Chip8Error::Io("Internal IO error: ", Some(err))
    }
}
<commit_msg>Derive Debug for Chip8Error<commit_after>//! `std:error:Error` implementations

use std::fmt;
use std::io;
use std::error::{Error, FromError};

/// `Error` variants for public errors in this crate
#[derive(Debug)]
pub enum Chip8Error {
    /// I/O error
    Io(&'static str, Option<io::Error>),
}

impl fmt::Display for Chip8Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        return write!(fmt, "{}", self.description())
    }
}

impl Error for Chip8Error {
    fn description(&self) -> &str {
        match *self {
            Chip8Error::Io(desc, _) => desc,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            Chip8Error::Io(_, Some(ref cause)) => Some(cause),
            _ => None,
        }
    }
}

impl FromError<io::Error> for Chip8Error {
    fn from_error(err: io::Error) -> Chip8Error {
        Chip8Error::Io("Internal IO error: ", Some(err))
    }
}
<|endoftext|>


<commit_before>// use std::backtrace::Backtrace;
use std::error::Error as StdError;
use std::fmt::{self, Write};
use std::io::Error as IOError;
use std::num::ParseIntError;
use std::string::FromUtf8Error;

use serde_json::error::Error as SerdeError;
use thiserror::Error;

#[cfg(feature = "dir_source")]
use walkdir::Error as WalkdirError;

#[cfg(feature = "script_helper")]
use rhai::{EvalAltResult, ParseError};

/// Error when rendering data on template.
#[derive(Debug, Default, Error)]
pub struct RenderError {
    pub desc: String,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    #[source]
    cause: Option<Box<dyn StdError + Send + Sync + 'static>>,
    unimplemented: bool,
    // backtrace: Backtrace,
}

impl fmt::Display for RenderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no) {
            (Some(line), Some(col)) => write!(
                f,
                "Error rendering \"{}\" line {}, col {}: {}",
                self.template_name.as_deref().unwrap_or("Unnamed template"),
                line,
                col,
                self.desc
            ),
            _ => write!(f, "{}", self.desc),
        }
    }
}

impl From<IOError> for RenderError {
    fn from(e: IOError) -> RenderError {
        RenderError::from_error("Cannot generate output.", e)
    }
}

impl From<SerdeError> for RenderError {
    fn from(e: SerdeError) -> RenderError {
        RenderError::from_error("Failed to access JSON data.", e)
    }
}

impl From<FromUtf8Error> for RenderError {
    fn from(e: FromUtf8Error) -> RenderError {
        RenderError::from_error("Failed to generate bytes.", e)
    }
}

impl From<ParseIntError> for RenderError {
    fn from(e: ParseIntError) -> RenderError {
        RenderError::from_error("Cannot access array/vector with string index.", e)
    }
}

impl From<TemplateError> for RenderError {
    fn from(e: TemplateError) -> RenderError {
        RenderError::from_error("Failed to parse template.", e)
    }
}

#[cfg(feature = "script_helper")]
impl From<Box<EvalAltResult>> for RenderError {
    fn from(e: Box<EvalAltResult>) -> RenderError {
        RenderError::from_error("Cannot convert data to Rhai dynamic", e)
    }
}

#[cfg(feature = "script_helper")]
impl From<ScriptError> for RenderError {
    fn from(e: ScriptError) -> RenderError {
        RenderError::from_error("Failed to load rhai script", e)
    }
}

impl RenderError {
    pub fn new<T: AsRef<str>>(desc: T) -> RenderError {
        RenderError {
            desc: desc.as_ref().to_owned(),
            ..Default::default()
        }
    }

    pub(crate) fn unimplemented() -> RenderError {
        RenderError {
            unimplemented: true,
            ..Default::default()
        }
    }

    pub fn strict_error(path: Option<&String>) -> RenderError {
        let msg = match path {
            Some(path) => format!("Variable {:?} not found in strict mode.", path),
            None => "Value is missing in strict mode".to_owned(),
        };
        RenderError::new(&msg)
    }

    pub fn from_error<E>(error_info: &str, cause: E) -> RenderError
    where
        E: StdError + Send + Sync + 'static,
    {
        let mut e = RenderError::new(error_info);
        e.cause = Some(Box::new(cause));

        e
    }

    #[inline]
    pub(crate) fn is_unimplemented(&self) -> bool {
        self.unimplemented
    }
}

/// Template parsing error
#[derive(Debug, Error)]
pub enum TemplateErrorReason {
    #[error("helper {0:?} was opened, but {1:?} is closing")]
    MismatchingClosedHelper(String, String),
    #[error("decorator {0:?} was opened, but {1:?} is closing")]
    MismatchingClosedDecorator(String, String),
    #[error("invalid handlebars syntax.")]
    InvalidSyntax,
    #[error("invalid parameter {0:?}")]
    InvalidParam(String),
    #[error("nested subexpression is not supported")]
    NestedSubexpression,
    #[error("Template \"{1}\": {0}")]
    IoError(IOError, String),
    #[cfg(feature = "dir_source")]
    #[error("Walk dir error: {err}")]
    WalkdirError {
        #[from]
        err: WalkdirError,
    },
}

/// Error on parsing template.
#[derive(Debug, Error)]
pub struct TemplateError {
    pub reason: TemplateErrorReason,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    segment: Option<String>,
}

impl TemplateError {
    pub fn of(e: TemplateErrorReason) -> TemplateError {
        TemplateError {
            reason: e,
            template_name: None,
            line_no: None,
            column_no: None,
            segment: None,
        }
    }

    pub fn at(mut self, template_str: &str, line_no: usize, column_no: usize) -> TemplateError {
        self.line_no = Some(line_no);
        self.column_no = Some(column_no);
        self.segment = Some(template_segment(template_str, line_no, column_no));
        self
    }

    pub fn in_template(mut self, name: String) -> TemplateError {
        self.template_name = Some(name);
        self
    }
}

impl From<(IOError, String)> for TemplateError {
    fn from(err_info: (IOError, String)) -> TemplateError {
        let (e, name) = err_info;
        TemplateError::of(TemplateErrorReason::IoError(e, name))
    }
}

#[cfg(feature = "dir_source")]
impl From<WalkdirError> for TemplateError {
    fn from(e: WalkdirError) -> TemplateError {
        TemplateError::of(TemplateErrorReason::from(e))
    }
}

fn template_segment(template_str: &str, line: usize, col: usize) -> String {
    let range = 3;
    let line_start = if line >= range { line - range } else { 0 };
    let line_end = line + range;

    let mut buf = String::new();
    for (line_count, line_content) in template_str.lines().enumerate() {
        if line_count >= line_start && line_count <= line_end {
            let _ = writeln!(&mut buf, "{:4} | {}", line_count, line_content);
            if line_count == line - 1 {
                buf.push_str("     |");
                for c in 0..line_content.len() {
                    if c != col {
                        buf.push('-');
                    } else {
                        buf.push('^');
                    }
                }
                buf.push('\n');
            }
        }
    }

    buf
}

impl fmt::Display for TemplateError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no, &self.segment) {
            (Some(line), Some(col), &Some(ref seg)) => writeln!(
                f,
                "Template error: {}\n    --> Template error in \"{}\":{}:{}\n     |\n{}     |\n     = reason: {}",
                self.reason,
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned()),
                line,
                col,
                seg,
                self.reason
            ),
            _ => write!(f, "{}", self.reason),
        }
    }
}

#[cfg(feature = "script_helper")]
#[derive(Debug, Error)]
pub enum ScriptError {
    #[error(transparent)]
    IoError(#[from] IOError),

    #[error(transparent)]
    ParseError(#[from] ParseError),
}
<commit_msg>fix: wrap template error in box<commit_after>// use std::backtrace::Backtrace;
use std::error::Error as StdError;
use std::fmt::{self, Write};
use std::io::Error as IOError;
use std::num::ParseIntError;
use std::string::FromUtf8Error;

use serde_json::error::Error as SerdeError;
use thiserror::Error;

#[cfg(feature = "dir_source")]
use walkdir::Error as WalkdirError;

#[cfg(feature = "script_helper")]
use rhai::{EvalAltResult, ParseError};

/// Error when rendering data on template.
#[derive(Debug, Default, Error)]
pub struct RenderError {
    pub desc: String,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    #[source]
    cause: Option<Box<dyn StdError + Send + Sync + 'static>>,
    unimplemented: bool,
    // backtrace: Backtrace,
}

impl fmt::Display for RenderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no) {
            (Some(line), Some(col)) => write!(
                f,
                "Error rendering \"{}\" line {}, col {}: {}",
                self.template_name.as_deref().unwrap_or("Unnamed template"),
                line,
                col,
                self.desc
            ),
            _ => write!(f, "{}", self.desc),
        }
    }
}

impl From<IOError> for RenderError {
    fn from(e: IOError) -> RenderError {
        RenderError::from_error("Cannot generate output.", e)
    }
}

impl From<SerdeError> for RenderError {
    fn from(e: SerdeError) -> RenderError {
        RenderError::from_error("Failed to access JSON data.", e)
    }
}

impl From<FromUtf8Error> for RenderError {
    fn from(e: FromUtf8Error) -> RenderError {
        RenderError::from_error("Failed to generate bytes.", e)
    }
}

impl From<ParseIntError> for RenderError {
    fn from(e: ParseIntError) -> RenderError {
        RenderError::from_error("Cannot access array/vector with string index.", e)
    }
}

impl From<TemplateError> for RenderError {
    fn from(e: TemplateError) -> RenderError {
        RenderError::from_error("Failed to parse template.", e)
    }
}

#[cfg(feature = "script_helper")]
impl From<Box<EvalAltResult>> for RenderError {
    fn from(e: Box<EvalAltResult>) -> RenderError {
        RenderError::from_error("Cannot convert data to Rhai dynamic", e)
    }
}

#[cfg(feature = "script_helper")]
impl From<ScriptError> for RenderError {
    fn from(e: ScriptError) -> RenderError {
        RenderError::from_error("Failed to load rhai script", e)
    }
}

impl RenderError {
    pub fn new<T: AsRef<str>>(desc: T) -> RenderError {
        RenderError {
            desc: desc.as_ref().to_owned(),
            ..Default::default()
        }
    }

    pub(crate) fn unimplemented() -> RenderError {
        RenderError {
            unimplemented: true,
            ..Default::default()
        }
    }

    pub fn strict_error(path: Option<&String>) -> RenderError {
        let msg = match path {
            Some(path) => format!("Variable {:?} not found in strict mode.", path),
            None => "Value is missing in strict mode".to_owned(),
        };
        RenderError::new(&msg)
    }

    pub fn from_error<E>(error_info: &str, cause: E) -> RenderError
    where
        E: StdError + Send + Sync + 'static,
    {
        let mut e = RenderError::new(error_info);
        e.cause = Some(Box::new(cause));

        e
    }

    #[inline]
    pub(crate) fn is_unimplemented(&self) -> bool {
        self.unimplemented
    }
}

/// Template parsing error
#[derive(Debug, Error)]
pub enum TemplateErrorReason {
    #[error("helper {0:?} was opened, but {1:?} is closing")]
    MismatchingClosedHelper(String, String),
    #[error("decorator {0:?} was opened, but {1:?} is closing")]
    MismatchingClosedDecorator(String, String),
    #[error("invalid handlebars syntax.")]
    InvalidSyntax,
    #[error("invalid parameter {0:?}")]
    InvalidParam(String),
    #[error("nested subexpression is not supported")]
    NestedSubexpression,
    #[error("Template \"{1}\": {0}")]
    IoError(IOError, String),
    #[cfg(feature = "dir_source")]
    #[error("Walk dir error: {err}")]
    WalkdirError {
        #[from]
        err: WalkdirError,
    },
}

/// Error on parsing template.
#[derive(Debug, Error)]
pub struct TemplateError {
    pub reason: Box<TemplateErrorReason>,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    segment: Option<String>,
}

impl TemplateError {
    pub fn of(e: TemplateErrorReason) -> TemplateError {
        TemplateError {
            reason: Box::new(e),
            template_name: None,
            line_no: None,
            column_no: None,
            segment: None,
        }
    }

    pub fn at(mut self, template_str: &str, line_no: usize, column_no: usize) -> TemplateError {
        self.line_no = Some(line_no);
        self.column_no = Some(column_no);
        self.segment = Some(template_segment(template_str, line_no, column_no));
        self
    }

    pub fn in_template(mut self, name: String) -> TemplateError {
        self.template_name = Some(name);
        self
    }
}

impl From<(IOError, String)> for TemplateError {
    fn from(err_info: (IOError, String)) -> TemplateError {
        let (e, name) = err_info;
        TemplateError::of(TemplateErrorReason::IoError(e, name))
    }
}

#[cfg(feature = "dir_source")]
impl From<WalkdirError> for TemplateError {
    fn from(e: WalkdirError) -> TemplateError {
        TemplateError::of(TemplateErrorReason::from(e))
    }
}

fn template_segment(template_str: &str, line: usize, col: usize) -> String {
    let range = 3;
    let line_start = if line >= range { line - range } else { 0 };
    let line_end = line + range;

    let mut buf = String::new();
    for (line_count, line_content) in template_str.lines().enumerate() {
        if line_count >= line_start && line_count <= line_end {
            let _ = writeln!(&mut buf, "{:4} | {}", line_count, line_content);
            if line_count == line - 1 {
                buf.push_str("     |");
                for c in 0..line_content.len() {
                    if c != col {
                        buf.push('-');
                    } else {
                        buf.push('^');
                    }
                }
                buf.push('\n');
            }
        }
    }

    buf
}

impl fmt::Display for TemplateError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no, &self.segment) {
            (Some(line), Some(col), &Some(ref seg)) => writeln!(
                f,
                "Template error: {}\n    --> Template error in \"{}\":{}:{}\n     |\n{}     |\n     = reason: {}",
                self.reason,
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned()),
                line,
                col,
                seg,
                self.reason
            ),
            _ => write!(f, "{}", self.reason),
        }
    }
}

#[cfg(feature = "script_helper")]
#[derive(Debug, Error)]
pub enum ScriptError {
    #[error(transparent)]
    IoError(#[from] IOError),

    #[error(transparent)]
    ParseError(#[from] ParseError),
}
<|endoftext|>


<commit_before>use std::num::ParseIntError;

#[derive(Debug)]
pub enum SdpParserResult {
    ParserLineError   { message: String,
                        line: String },
    ParserUnsupported { message: String,
                        line: String },
    ParserSequence    { message: String,
                        line: Option<usize> },
}

impl From<ParseIntError> for SdpParserResult {
    fn from(_: ParseIntError) -> SdpParserResult {
        // TODO empty line error here makes no sense
        SdpParserResult::ParserLineError { message: "failed to parse integer".to_string(),
                                           line: "".to_string() }
    }
}

<commit_msg>rust formated<commit_after>use std::num::ParseIntError;

#[derive(Debug)]
pub enum SdpParserResult {
    ParserLineError { message: String, line: String },
    ParserUnsupported { message: String, line: String },
    ParserSequence {
        message: String,
        line: Option<usize>,
    },
}

impl From<ParseIntError> for SdpParserResult {
    fn from(_: ParseIntError) -> SdpParserResult {
        // TODO empty line error here makes no sense
        SdpParserResult::ParserLineError {
            message: "failed to parse integer".to_string(),
            line: "".to_string(),
        }
    }
}
<|endoftext|>


<commit_before>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::string;
use std::io;
use std::num;

error_chain! {

    errors {
        /// parser error
        Parse(t: ParseError, s: String) {
            description("parse error")
            display("parse error: '{}'", s)
        }
    }

    foreign_links {
        Io(io::Error) #[doc = "Json error"];
        FromUtf8(string::FromUtf8Error) #[doc = "Utf8 error"];
        Float(num::ParseFloatError) #[doc = "Float error"];
        Int(num::ParseIntError) #[doc = "Int error"];
    }
}

/// detailed symbolic-expression parse error information
#[derive(Debug)]
pub struct ParseError {
    msg: String,
    line: usize,
    col: usize,
}

/// utility function that creates a symbolic-expressions Error Result for a parser error
pub fn parse_error<T>(line: usize, col: usize, msg: String) -> Result<T> {
    let pe = ParseError {
        msg: msg,
        line: line,
        col: col,
    };
    let s = format!("Parse Error: {}:{} {}", line, col, pe.msg);
    Err(ErrorKind::Parse(pe, s).into())
}
<commit_msg>fix doc<commit_after>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::string;
use std::io;
use std::num;

error_chain! {

    errors {
        /// parser error
        Parse(t: ParseError, s: String) {
            description("parse error")
            display("parse error: '{}'", s)
        }
    }

    foreign_links {
        Io(io::Error) #[doc = "IO error"];
        FromUtf8(string::FromUtf8Error) #[doc = "Utf8 error"];
        Float(num::ParseFloatError) #[doc = "Float error"];
        Int(num::ParseIntError) #[doc = "Int error"];
    }
}

/// detailed symbolic-expression parse error information
#[derive(Debug)]
pub struct ParseError {
    msg: String,
    line: usize,
    col: usize,
}

/// utility function that creates a symbolic-expressions Error Result for a parser error
pub fn parse_error<T>(line: usize, col: usize, msg: String) -> Result<T> {
    let pe = ParseError {
        msg: msg,
        line: line,
        col: col,
    };
    let s = format!("Parse Error: {}:{} {}", line, col, pe.msg);
    Err(ErrorKind::Parse(pe, s).into())
}
<|endoftext|>