<commit_before>#![allow(dead_code)]

use std::fmt;
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;
use std::char;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Stone {
    Empty,
    White,
    Black,
}

impl Default for Stone {
    fn default() -> Stone {
        Stone::Empty
    }
}

impl fmt::Display for Stone {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}",
               match *self {
                   Stone::Empty => ".",
                   Stone::White => "O",
                   Stone::Black => "X",
               })
    }
}
#[derive(Clone, Copy, Debug)]
pub struct Point {
    pub x: u32,
    pub y: u32,
}

#[derive(Copy, Clone)]
pub struct BoardMarker {
    pub point: Point,
    pub color: Stone,
}

impl fmt::Debug for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "|[{:>2}, {} ]{:?}|", ((self.point.x as u8 + 65u8) as char), self.point.y, self.color)
    }
}

impl fmt::Display for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}",
               match self.color {
                   Stone::Empty => ".",
                   Stone::White => "O",
                   Stone::Black => "X",
               })
    }
}

impl Point {
    pub fn new(x: u32, y: u32) -> Point {
        Point { x: x, y: y }
    }
    pub fn from_1d(idx: u32, width: u32) -> Point {
        Point {
            x: idx % width,
            y: idx / width,
        }
    }
    pub fn to_1d(self, width: u32) -> u32 {
        self.x + self.y * width
    }
}

#[derive(Debug)]
pub struct BoardArr(Vec<BoardMarker>);

impl BoardArr {
    fn new() -> BoardArr {
        BoardArr(Vec::new())
    }

    fn add(&mut self, elem: BoardMarker) {
        self.0.push(elem);
    }
}

impl Deref for BoardArr {
    type Target = Vec<BoardMarker>;

    fn deref(&self) -> &Vec<BoardMarker> {
        &self.0
    }
}

impl DerefMut for BoardArr {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<BoardMarker> {
        &mut self.0
    }
}

#[derive(Debug)]
pub struct Board {
    pub boardsize: u32,
    pub last_move: Option<Point>,
    pub board: BoardArr,
}

impl fmt::Display for BoardArr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure if needed - let vec: Vec<BoardMarker> = *self;
        let mut dy: u32 = 0;
        let width: u32 = self.last().clone().unwrap().point.y + 1;
        write!(f, " 0:")?;
        for marker in self.iter() {
            if marker.point.y == dy {
                if marker.point.x != width {
                    write!(f, "{} ", marker)?;
                } else {
                    write!(f, "{}", marker)?;
                }
            } else {
                dy += 1;
                write!(f, "\n{:2}:{} ", dy, marker)?;
            }
        }
        write!(f, "\n   {}", (b'A' .. b'A' + 15)
                .map(|d| (d as char).to_string())
                .collect::<Vec<_>>().join(" "))
    }
}

impl Board {
    pub fn new(boardsize: u32) -> Board {
        let board: BoardArr = (0..boardsize * boardsize)
            .map(|idx|
                    BoardMarker { point: Point::from_1d(idx, boardsize),
                                color: Stone::Empty }
            ).collect();

        Board {
            boardsize: boardsize,
            last_move: None,
            board: board,
        }
    }
    pub fn clear(&mut self) {
        self.board = (0..self.boardsize * self.boardsize)
            .map(|idx|
                {
                     BoardMarker { point: Point::from_1d(idx, self.boardsize),  color: Stone::Empty,
                             }
                         })
                         .collect();
    }
    // FIXME: Use `Result` instead of Option
    pub fn get(&self, pos: Point) -> Option<&BoardMarker> {
        self.board.get(pos.to_1d(self.boardsize) as usize)
    }

    pub fn getxy(&self, x: u32, y: u32) -> Option<&BoardMarker> {
        self.board.get((x + y * self.boardsize) as usize)
    }
    pub fn get_mut(&mut self, pos: Point) -> Option<&mut BoardMarker> {
        self.board.get_mut(pos.to_1d(self.boardsize) as usize)
    }

    pub fn set_point(&mut self, pos: Point, color: Stone) {
        self.board[pos.to_1d(self.boardsize) as usize].color = color;
    }
}

impl FromIterator<BoardMarker> for BoardArr {
    fn from_iter<I: IntoIterator<Item = BoardMarker>>(iterator: I) -> Self {
        let mut c = BoardArr::new();

        for i in iterator {
            c.add(i);
        }
        c
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn check_if_board_works() {
        let mut board = Board::new(15);
        assert_eq!(board.board.len(), 15 * 15);
        let p = Point { x: 0, y: 0 };
        board.set_point(p, Stone::White);
        assert_eq!(board.get(p).unwrap().color, Stone::White);
        let p = Point { x: 3, y: 2 };
        board.set_point(p, Stone::Black);
        assert_eq!(board.get(p).unwrap().color, Stone::Black);
        // println!("{:?}", board);
        println!("test:check_if_board_works:Board\n{}", board.board);
    }

    #[test]
    fn clear_board() {
        let mut board = Board::new(15);
        let p = Point { x: 7, y: 7 };
        board.set_point(p, Stone::White);
        println!("test:clear_board:Board:\n{}", board.board);
        board.clear();
        println!("test:clear_board:Board(Cleared):\n{}", board.board);
        assert_eq!(board.get(p).unwrap().color, Stone::Empty);
    }
}
<commit_msg>Changed test output<commit_after>#![allow(dead_code)]

use std::fmt;
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;
use std::char;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Stone {
    Empty,
    White,
    Black,
}

impl Default for Stone {
    fn default() -> Stone {
        Stone::Empty
    }
}

impl fmt::Display for Stone {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}",
               match *self {
                   Stone::Empty => ".",
                   Stone::White => "O",
                   Stone::Black => "X",
               })
    }
}
#[derive(Clone, Copy, Debug)]
pub struct Point {
    pub x: u32,
    pub y: u32,
}

#[derive(Copy, Clone)]
pub struct BoardMarker {
    pub point: Point,
    pub color: Stone,
}

impl fmt::Debug for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "|[{:>2}, {} ]{:?}|", ((self.point.x as u8 + 65u8) as char), self.point.y, self.color)
    }
}

impl fmt::Display for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}",
               match self.color {
                   Stone::Empty => ".",
                   Stone::White => "O",
                   Stone::Black => "X",
               })
    }
}

impl Point {
    pub fn new(x: u32, y: u32) -> Point {
        Point { x: x, y: y }
    }
    pub fn from_1d(idx: u32, width: u32) -> Point {
        Point {
            x: idx % width,
            y: idx / width,
        }
    }
    pub fn to_1d(self, width: u32) -> u32 {
        self.x + self.y * width
    }
}

#[derive(Debug)]
pub struct BoardArr(Vec<BoardMarker>);

impl BoardArr {
    fn new() -> BoardArr {
        BoardArr(Vec::new())
    }

    fn add(&mut self, elem: BoardMarker) {
        self.0.push(elem);
    }
}

impl Deref for BoardArr {
    type Target = Vec<BoardMarker>;

    fn deref(&self) -> &Vec<BoardMarker> {
        &self.0
    }
}

impl DerefMut for BoardArr {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<BoardMarker> {
        &mut self.0
    }
}

#[derive(Debug)]
pub struct Board {
    pub boardsize: u32,
    pub last_move: Option<Point>,
    pub board: BoardArr,
}

impl fmt::Display for BoardArr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure if needed - let vec: Vec<BoardMarker> = *self;
        let mut dy: u32 = 0;
        let width: u32 = self.last().clone().unwrap().point.y + 1;
        write!(f, " 0:")?;
        for marker in self.iter() {
            if marker.point.y == dy {
                if marker.point.x != width {
                    write!(f, "{} ", marker)?;
                } else {
                    write!(f, "{}", marker)?;
                }
            } else {
                dy += 1;
                write!(f, "\n{:2}:{} ", dy, marker)?;
            }
        }
        write!(f, "\n   {}", (b'A' .. b'A' + 15)
                .map(|d| (d as char).to_string())
                .collect::<Vec<_>>().join(" "))
    }
}

impl Board {
    pub fn new(boardsize: u32) -> Board {
        let board: BoardArr = (0..boardsize * boardsize)
            .map(|idx|
                    BoardMarker { point: Point::from_1d(idx, boardsize),
                                color: Stone::Empty }
            ).collect();

        Board {
            boardsize: boardsize,
            last_move: None,
            board: board,
        }
    }
    pub fn clear(&mut self) {
        self.board = (0..self.boardsize * self.boardsize)
            .map(|idx|
                {
                     BoardMarker { point: Point::from_1d(idx, self.boardsize),  color: Stone::Empty,
                             }
                         })
                         .collect();
    }
    // FIXME: Use `Result` instead of Option
    pub fn get(&self, pos: Point) -> Option<&BoardMarker> {
        self.board.get(pos.to_1d(self.boardsize) as usize)
    }

    pub fn getxy(&self, x: u32, y: u32) -> Option<&BoardMarker> {
        self.board.get((x + y * self.boardsize) as usize)
    }
    pub fn get_mut(&mut self, pos: Point) -> Option<&mut BoardMarker> {
        self.board.get_mut(pos.to_1d(self.boardsize) as usize)
    }

    pub fn set_point(&mut self, pos: Point, color: Stone) {
        self.board[pos.to_1d(self.boardsize) as usize].color = color;
    }
}

impl FromIterator<BoardMarker> for BoardArr {
    fn from_iter<I: IntoIterator<Item = BoardMarker>>(iterator: I) -> Self {
        let mut c = BoardArr::new();

        for i in iterator {
            c.add(i);
        }
        c
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn check_if_board_works() {
        let mut board = Board::new(15);
        assert_eq!(board.board.len(), 15 * 15);
        let p = Point { x: 0, y: 0 };
        board.set_point(p, Stone::White);
        assert_eq!(board.get(p).unwrap().color, Stone::White);
        let p = Point { x: 3, y: 2 };
        board.set_point(p, Stone::Black);
        assert_eq!(board.get(p).unwrap().color, Stone::Black);
        // println!("{:?}", board);
        println!("Board\n{}", board.board);
    }

    #[test]
    fn clear_board() {
        let mut board = Board::new(15);
        let p = Point { x: 7, y: 7 };
        board.set_point(p, Stone::White);
        println!("Board:\n{}", board.board);
        board.clear();
        println!("Board - Cleared:\n{}", board.board);
        assert_eq!(board.get(p).unwrap().color, Stone::Empty);
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Result;

pub enum Message {
    KeepAlive,
    Choke,
    Unchoke,
    Interested,
    NotInterested,
    Have {piece_index: u32},
    Bitfield(Vec<u8>)

}

///len_prefix is big endian
///might want to use traits instead of returning an enum... haven't decided yet. would save a match
pub fn decode_message <T> (len_prefix: &[u8; 4], stream: &mut T) -> Message where T:Read {
    let i = u8_4_to_u32(len_prefix);
    match i {
        0 => Message::KeepAlive,
        len => {
            let mut id_buf = [0; 1];
            let _ = stream.read(&mut id_buf);
            match id_buf[0] {
                0 => Message::Choke,
                1 => Message::Unchoke,
                2 => Message::Interested,
                3 => Message::NotInterested,
                4 => {
                    let mut buf = [0; 4];
                    stream.read(&mut buf);
                    let piece_index = u8_4_to_u32(&buf);
                    Message::Have{piece_index: piece_index}
                },
                5 => {
                    let bitfield_length = len - 1;
                    Message::Bitfield(read_out_variable(stream, bitfield_length as u64))
                }
                _ => Message::Choke
            }

        }
    }
}

fn u8_4_to_u32 (bytes: &[u8; 4]) -> u32 {
    (bytes[3] as u32
        | ((bytes[2] as u32) << 8)
        | ((bytes[1] as u32) << 16)
        | ((bytes[0] as u32) << 24))
}

fn read_out_variable <T> (stream: &mut T, num_bytes: u64) -> Vec<u8> where T:Read {
    let mut buf = Vec::new();
    stream.take(num_bytes).read(&mut buf);
    buf
}

pub fn test () {
    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, &mut stream);
}

#[test]
fn test_decode () {

    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, stream);
}
<commit_msg>added all deserializers for standard messages<commit_after>use std::io::Read;
use std::io::Result;

pub enum Message {
    KeepAlive,
    Choke,
    Unchoke,
    Interested,
    NotInterested,
    Have {piece_index: u32},
    Bitfield(Vec<u8>),
    Request {index: u32, begin: u32, length: u32},
    Piece {index: u32, begin: u32, block: Vec<u8>},
    Cancel {index: u32, begin: u32, length: u32},
    Port(u16),
    Unhandled
}

///len_prefix is big endian
///might want to use traits instead of returning an enum... haven't decided yet. would save a match
pub fn decode_message <T> (len_prefix: &[u8; 4], stream: &mut T) -> Message where T:Read {
    let i = u8_4_to_u32(len_prefix);
    match i {
        0 => Message::KeepAlive,
        len => {
            let mut id_buf = [0; 1];
            let _ = stream.read(&mut id_buf);
            match id_buf[0] {
                0 => Message::Choke,
                1 => Message::Unchoke,
                2 => Message::Interested,
                3 => Message::NotInterested,
                4 => {
                    let piece_index = read_word(stream);
                    Message::Have{piece_index: piece_index}
                },
                5 => {
                    let bitfield_length = len - 1;
                    Message::Bitfield(read_out_variable(stream, bitfield_length as u64))
                },
                6 => {
                    //so much for referential transparency... ah my eyes!
                    let index = read_word(stream);
                    let begin = read_word(stream);
                    let length = read_word(stream);
                    Message::Request{index: index, begin: begin, length: length}
                },
                7 => {
                    let block_length = len - 9;
                    //TODO: for the sake of semi-immutability maybe it would be prettier if we
                    //consume from the stream in one operation, then partition the slice up
                    //appropriately after
                    let index = read_word(stream);
                    let begin = read_word(stream);
                    let block = read_out_variable(stream, block_length as u64);
                    Message::Piece{index: index, begin: begin, block: block}
                },
                8 => {
                    let index = read_word(stream);
                    let begin = read_word(stream);
                    let length = read_word(stream);
                    Message::Cancel{index: index, begin: begin, length: length}
                },
                9 =>{
                    let mut buf = [0; 2];
                    stream.read(&mut buf);
                    let port = u8_2_to_u16(&buf);
                    Message::Port(port)
                }
                _ => Message::Unhandled
            }

        }
    }
}

//the following two definitions feel clunky. can probably genericize over num bytes somehow
fn u8_2_to_u16 (bytes: &[u8; 2]) -> u16 {
    (bytes[1] as u16 | (bytes[0] as u16) << 8)
}

fn u8_4_to_u32 (bytes: &[u8; 4]) -> u32 {
    (bytes[3] as u32
        | ((bytes[2] as u32) << 8)
        | ((bytes[1] as u32) << 16)
        | ((bytes[0] as u32) << 24))
}

//reads into a fixed length u32
fn read_word <T> (stream: &mut T) -> u32 where T:Read {
    let mut buf = [0; 4];
    stream.read(&mut buf);
    u8_4_to_u32(&buf)
}

fn read_out_variable <T> (stream: &mut T, num_bytes: u64) -> Vec<u8> where T:Read {
    let mut buf = Vec::new();
    stream.take(num_bytes).read(&mut buf);
    buf
}

pub fn test () {
    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, &mut stream);
}

#[test]
fn test_decode () {

    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, stream);
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Example of handling Result variants with match (Ok and Err)<commit_after>use std::fs::File;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("Problem with opening file: {:?}", error)
        },
    };
}
<|endoftext|>


<commit_before>#[macro_use] extern crate scan_rules;
#[macro_use] mod util;

use scan_rules::ScanError as SE;
use scan_rules::ScanErrorKind as SEK;

#[test]
fn test_repeating() {
    assert_match!(
        scan!("[]"; ("[", [ let ns: i32 ]?, "]") => ns),
        Ok(ref ns) if *ns == vec![]
    );

    assert_match!(
        scan!("[]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![]
    );

    assert_match!(
        scan!("[]"; ("[", [ let ns: i32 ]+, "]") => ns),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("[0]"; ("[", [ let ns: i32 ]?, "]") => ns),
        Ok(ref ns) if *ns == vec![0]
    );

    assert_match!(
        scan!("[0]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![0]
    );

    assert_match!(
        scan!("[0]"; ("[", [ let ns: i32 ]+, "]") => ns),
        Ok(ref ns) if *ns == vec![0]
    );

    assert_match!(
        scan!("[0 1]"; ("[", [ let ns: i32 ]?, "]") => ns),
        Err(SE { ref at, kind: SEK::LiteralMismatch }) if at.offset() == 3
    );

    assert_match!(
        scan!("[0 1]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("[0 1]"; ("[", [ let ns: i32 ]+, "]") => ns),
        Ok(ref ns) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("[0 1 2 3]"; ("[", [ let _: i32 ]*, "]") => ()),
        Ok(())
    );

    assert_match!(
        scan!("[0 1 2 3]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![0, 1, 2, 3]
    );

    assert_match!(
        scan!("[0 1 2 3]"; ("[", [ let xs: i32, let ys: i32 ]*, "]") => (xs, ys)),
        Ok((ref xs, ref ys)) if &**xs == [0, 2] && &**ys == [1, 3]
    );

    assert_match!(
        scan!("[[0 1] [2 3]]"; ("[", ["[", [let nss: i32]*, "]"]*, "]") => nss),
        Ok(ref ns) if *ns == vec![vec![0, 1], vec![2, 3]]
    );

    assert_match!(
        scan!("[0 [1 2] 3 [4 5]]"; ("[", [let xs: i32, "[", [let yss: i32]*, "]"]*, "]") => (xs, yss)),
        Ok((ref xs, ref yss)) if *xs == vec![0, 3] && *yss == vec![vec![1, 2], vec![4, 5]]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{2}, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{2}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{2}, ..tail) => (ns, tail)),
        Ok((ref ns, " 2")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0 1 2 3"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0 1 2 3"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!(""; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0,"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 2
    );

    assert_match!(
        scan!("0, 1, 2, 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2, 3]
    );

    assert_match!(
        scan!("0, 1, 2 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0, 1 2, 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, " 2, 3")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1, 2, 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, " 1, 2, 3")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0, 1, 2, 3,"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 11
    );

    assert_match!(
        scan!("0 and 1 and 2 and 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2, 3]
    );

    assert_match!(
        scan!("0 and 1 and 2 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0 and 1 2 and 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, " 2 and 3")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 and 2 and 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, " 1 and 2 and 3")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0 and 1 and 2 and 3 and"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 23
    );

    assert_match!(
        scan!("0 and 1 and 2 and 3"; ([ let ns: i32 ]( let sep: &str )*, ..tail) => (ns, sep, tail)),
        Ok((ref ns, ref sep, "")) if *ns == vec![0, 1, 2, 3] && *sep == vec!["and", "and", "and"]
    );
}
<commit_msg>Added missing tests for repeating patterns.<commit_after>#[macro_use] extern crate scan_rules;
#[macro_use] mod util;

use scan_rules::ScanError as SE;
use scan_rules::ScanErrorKind as SEK;

#[test]
fn test_repeating() {
    assert_match!(
        scan!("[]"; ("[", [ let ns: i32 ]?, "]") => ns),
        Ok(ref ns) if *ns == vec![]
    );

    assert_match!(
        scan!("[]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![]
    );

    assert_match!(
        scan!("[]"; ("[", [ let ns: i32 ]+, "]") => ns),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("[0]"; ("[", [ let ns: i32 ]?, "]") => ns),
        Ok(ref ns) if *ns == vec![0]
    );

    assert_match!(
        scan!("[0]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![0]
    );

    assert_match!(
        scan!("[0]"; ("[", [ let ns: i32 ]+, "]") => ns),
        Ok(ref ns) if *ns == vec![0]
    );

    assert_match!(
        scan!("[0 1]"; ("[", [ let ns: i32 ]?, "]") => ns),
        Err(SE { ref at, kind: SEK::LiteralMismatch }) if at.offset() == 3
    );

    assert_match!(
        scan!("[0 1]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("[0 1]"; ("[", [ let ns: i32 ]+, "]") => ns),
        Ok(ref ns) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("[0 1 2 3]"; ("[", [ let _: i32 ]*, "]") => ()),
        Ok(())
    );

    assert_match!(
        scan!("[0 1 2 3]"; ("[", [ let ns: i32 ]*, "]") => ns),
        Ok(ref ns) if *ns == vec![0, 1, 2, 3]
    );

    assert_match!(
        scan!("[0 1 2 3]"; ("[", [ let xs: i32, let ys: i32 ]*, "]") => (xs, ys)),
        Ok((ref xs, ref ys)) if &**xs == [0, 2] && &**ys == [1, 3]
    );

    assert_match!(
        scan!("[[0 1] [2 3]]"; ("[", ["[", [let nss: i32]*, "]"]*, "]") => nss),
        Ok(ref ns) if *ns == vec![vec![0, 1], vec![2, 3]]
    );

    assert_match!(
        scan!("[0 [1 2] 3 [4 5]]"; ("[", [let xs: i32, "[", [let yss: i32]*, "]"]*, "]") => (xs, yss)),
        Ok((ref xs, ref yss)) if *xs == vec![0, 3] && *yss == vec![vec![1, 2], vec![4, 5]]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{2}, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{2}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{2}, ..tail) => (ns, tail)),
        Ok((ref ns, " 2")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{2,}, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{2,}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{2,}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 1
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0 1 2 3"; ([ let ns: i32 ]{2, 3}, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0 1"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 2"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0 1 2 3"; ([ let ns: i32 ]{,3}, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!(""; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![]
    );

    assert_match!(
        scan!("0"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0,"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 2
    );

    assert_match!(
        scan!("0, 1, 2, 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2, 3]
    );

    assert_match!(
        scan!("0, 1, 2 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0, 1 2, 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, " 2, 3")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1, 2, 3"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Ok((ref ns, " 1, 2, 3")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0, 1, 2, 3,"; ([ let ns: i32 ],*, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 11
    );

    assert_match!(
        scan!("0 and 1 and 2 and 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, "")) if *ns == vec![0, 1, 2, 3]
    );

    assert_match!(
        scan!("0 and 1 and 2 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, " 3")) if *ns == vec![0, 1, 2]
    );

    assert_match!(
        scan!("0 and 1 2 and 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, " 2 and 3")) if *ns == vec![0, 1]
    );

    assert_match!(
        scan!("0 1 and 2 and 3"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Ok((ref ns, " 1 and 2 and 3")) if *ns == vec![0]
    );

    assert_match!(
        scan!("0 and 1 and 2 and 3 and"; ([ let ns: i32 ]("and")*, ..tail) => (ns, tail)),
        Err(SE { ref at, kind: SEK::Missing }) if at.offset() == 23
    );

    assert_match!(
        scan!("0 and 1 and 2 and 3"; ([ let ns: i32 ]( let sep: &str )*, ..tail) => (ns, sep, tail)),
        Ok((ref ns, ref sep, "")) if *ns == vec![0, 1, 2, 3] && *sep == vec!["and", "and", "and"]
    );
}
<|endoftext|>


<commit_before>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

// Crate imports
extern crate num_traits;

// Module imports
use self::num_traits::{Num, NumCast};

use ::vector::{Vec2, Vec3, Vec4};

use std::convert::From;

/*===============================================================================================*/
/*------RGBA STRUCT------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// Stores a RGBA colour value.
#[cfg_attr (feature = "serde_serialize", derive (Deserialize, Serialize))]
#[derive (Copy, Clone, Debug, PartialEq)]
pub struct RGBA {

    // Public
    /// Red channel.
    pub r: f32,
    /// Green channel.
    pub g: f32,
    /// Blue channel.
    pub b: f32,
    /// Alpha channel.
    pub a: f32,
}

/*===============================================================================================*/
/*------RGBA TRAIT IMPLEMENTATIONS---------------------------------------------------------------*/
/*===============================================================================================*/

impl Default for RGBA {

    fn default () -> Self {
        RGBA::from (1.0)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl From<f32> for RGBA {

    fn from (value: f32) -> Self {
        RGBA::new (value, value, value, value)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl<T> From<Vec2<T>> for RGBA where
    T: Copy + Num + NumCast {

    fn from (value: Vec2<T>) -> Self {

        RGBA::new (value.x.to_f32 ().unwrap (),
                   value.y.to_f32 ().unwrap (),
                   0.0, 1.0)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl<T> From<Vec3<T>> for RGBA where
    T: Copy + Num + NumCast {

    fn from (value: Vec3<T>) -> Self {

        RGBA::new (value.x.to_f32 ().unwrap (),
                   value.y.to_f32 ().unwrap (),
                   value.z.to_f32 ().unwrap (),
                   1.0)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl<T> From<Vec4<T>> for RGBA where
    T: Copy + Num + NumCast {

    fn from (value: Vec4<T>) -> Self {

        RGBA::new (value.x.to_f32 ().unwrap (),
                   value.y.to_f32 ().unwrap (),
                   value.z.to_f32 ().unwrap (),
                   value.w.to_f32 ().unwrap ())
    }
}

/*===============================================================================================*/
/*------RGBA PUBLIC METHODS----------------------------------------------------------------------*/
/*===============================================================================================*/

impl RGBA {

    /// Returns a new `RGBA` instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::new (0.0, 1.0, 0.5, 1.0);
    /// ```
    pub fn new (r: f32, g: f32, b: f32, a: f32) -> Self {
        RGBA {r: r, g: g, b: b, a: a}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour black.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::black ();
    /// ```
    pub fn black () -> Self {
        RGBA::new (0.0, 0.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour light grey.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::light_grey ();
    /// ```
    pub fn light_grey () -> Self {
        RGBA::new (0.75, 0.75, 0.75, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour grey.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::grey ();
    /// ```
    pub fn grey () -> Self {
        RGBA::new (0.5, 0.5, 0.5, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour dark grey.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::dark_grey ();
    /// ```
    pub fn dark_grey () -> Self {
        RGBA::new (0.25, 0.25, 0.25, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour white.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::white ();
    /// ```
    pub fn white () -> Self {
        RGBA::from (1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour red.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::red ();
    /// ```
    pub fn red () -> Self {
        RGBA::new (1.0, 0.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour green.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::green ();
    /// ```
    pub fn green () -> Self {
        RGBA::new (0.0, 1.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour blue.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::blue ();
    /// ```
    pub fn blue () -> Self {
        RGBA::new (0.0, 0.0, 1.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour yellow.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::yellow ();
    /// ```
    pub fn yellow () -> Self {
        RGBA::new (1.0, 1.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour cyan.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::cyan ();
    /// ```
    pub fn cyan () -> Self {
        RGBA::new (0.0, 1.0, 1.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour magenta.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::magenta ();
    /// ```
    pub fn magenta () -> Self {
        RGBA::new (1.0, 0.0, 1.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a fully transparent colour.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::transparent ();
    /// ```
    pub fn transparent () -> Self {
        RGBA::from (0.0)
    }
}
<commit_msg>Implemented Clamp and Lerp traits<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

// Crate imports
extern crate num_traits;

// Module imports
use self::num_traits::{Num, NumCast};

use ::util::{Clamp, Lerp};
use ::vector::{Vec2, Vec3, Vec4};

use std::convert::From;

/*===============================================================================================*/
/*------RGBA STRUCT------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// Stores a RGBA colour value.
#[cfg_attr (feature = "serde_serialize", derive (Deserialize, Serialize))]
#[derive (Copy, Clone, Debug, PartialEq)]
pub struct RGBA {

    // Public
    /// Red channel.
    pub r: f32,
    /// Green channel.
    pub g: f32,
    /// Blue channel.
    pub b: f32,
    /// Alpha channel.
    pub a: f32,
}

/*===============================================================================================*/
/*------RGBA TRAIT IMPLEMENTATIONS---------------------------------------------------------------*/
/*===============================================================================================*/

impl Clamp for RGBA {

    fn clamp (self, min: Self, max: Self) -> Self {

        debug_assert! (min.r < max.r, "Min cannot be greater than max.");
        debug_assert! (min.g < max.g, "Min cannot be greater than max.");
        debug_assert! (min.b < max.b, "Min cannot be greater than max.");
        debug_assert! (min.a < max.a, "Min cannot be greater than max.");

        let rval = if self.r < min.r {min.r} else if self.r > max.r {max.r} else {self.r};
        let gval = if self.g < min.g {min.g} else if self.g > max.g {max.g} else {self.g};
        let bval = if self.b < min.b {min.b} else if self.b > max.b {max.b} else {self.b};
        let aval = if self.a < min.a {min.a} else if self.a > max.a {max.a} else {self.a};

        RGBA::new (rval, gval, bval, aval)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Default for RGBA {

    fn default () -> Self {
        RGBA::from (1.0)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl From<f32> for RGBA {

    fn from (value: f32) -> Self {
        RGBA::new (value, value, value, value)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl<T> From<Vec2<T>> for RGBA where
    T: Copy + Num + NumCast {

    fn from (value: Vec2<T>) -> Self {

        RGBA::new (value.x.to_f32 ().unwrap (),
                   value.y.to_f32 ().unwrap (),
                   0.0, 1.0)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl<T> From<Vec3<T>> for RGBA where
    T: Copy + Num + NumCast {

    fn from (value: Vec3<T>) -> Self {

        RGBA::new (value.x.to_f32 ().unwrap (),
                   value.y.to_f32 ().unwrap (),
                   value.z.to_f32 ().unwrap (),
                   1.0)
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl<T> From<Vec4<T>> for RGBA where
    T: Copy + Num + NumCast {

    fn from (value: Vec4<T>) -> Self {

        RGBA::new (value.x.to_f32 ().unwrap (),
                   value.y.to_f32 ().unwrap (),
                   value.z.to_f32 ().unwrap (),
                   value.w.to_f32 ().unwrap ())
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Lerp for RGBA {

    fn lerp (start: Self, end: Self, percentage: f32) -> Self {

        RGBA::new (f32::lerp (start.r, end.r, percentage),
                   f32::lerp (start.g, end.g, percentage),
                   f32::lerp (start.b, end.b, percentage),
                   f32::lerp (start.a, end.a, percentage))
    }

/*-----------------------------------------------------------------------------------------------*/

    fn lerp_unclamped (start: Self, end: Self, percentage: f32) -> Self {

        RGBA::new (f32::lerp_unclamped (start.r, end.r, percentage),
                   f32::lerp_unclamped (start.g, end.g, percentage),
                   f32::lerp_unclamped (start.b, end.b, percentage),
                   f32::lerp_unclamped (start.a, end.a, percentage))
    }
}

/*===============================================================================================*/
/*------RGBA PUBLIC METHODS----------------------------------------------------------------------*/
/*===============================================================================================*/

impl RGBA {

    /// Returns a new `RGBA` instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::new (0.0, 1.0, 0.5, 1.0);
    /// ```
    pub fn new (r: f32, g: f32, b: f32, a: f32) -> Self {
        RGBA {r: r, g: g, b: b, a: a}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour black.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::black ();
    /// ```
    pub fn black () -> Self {
        RGBA::new (0.0, 0.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour light grey.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::light_grey ();
    /// ```
    pub fn light_grey () -> Self {
        RGBA::new (0.75, 0.75, 0.75, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour grey.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::grey ();
    /// ```
    pub fn grey () -> Self {
        RGBA::new (0.5, 0.5, 0.5, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour dark grey.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::dark_grey ();
    /// ```
    pub fn dark_grey () -> Self {
        RGBA::new (0.25, 0.25, 0.25, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour white.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::white ();
    /// ```
    pub fn white () -> Self {
        RGBA::from (1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour red.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::red ();
    /// ```
    pub fn red () -> Self {
        RGBA::new (1.0, 0.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour green.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::green ();
    /// ```
    pub fn green () -> Self {
        RGBA::new (0.0, 1.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour blue.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::blue ();
    /// ```
    pub fn blue () -> Self {
        RGBA::new (0.0, 0.0, 1.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour yellow.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::yellow ();
    /// ```
    pub fn yellow () -> Self {
        RGBA::new (1.0, 1.0, 0.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour cyan.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::cyan ();
    /// ```
    pub fn cyan () -> Self {
        RGBA::new (0.0, 1.0, 1.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the colour magenta.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::magenta ();
    /// ```
    pub fn magenta () -> Self {
        RGBA::new (1.0, 0.0, 1.0, 1.0)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a fully transparent colour.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::colour::RGBA;
    /// let colour = RGBA::transparent ();
    /// ```
    pub fn transparent () -> Self {
        RGBA::from (0.0)
    }
}
<|endoftext|>


<commit_before>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Sub, Mul};

pub use luminance::{Equation, Factor};

use color::ColorAlpha;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(ColorAlpha),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, ColorAlpha, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, other: Self, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(other), clear_color, eq, src_fct, dst_fct)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let program = self.program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let program = self.program.borrow();
    let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: ColorAlpha) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let program = self.program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<commit_msg>Added From<Color> for Node.<commit_after>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Sub, Mul};

pub use luminance::{Equation, Factor};

use color::ColorAlpha;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(ColorAlpha),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, ColorAlpha, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, other: Self, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(other), clear_color, eq, src_fct, dst_fct)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<ColorAlpha> for Node<'a> {
  fn from(color: ColorAlpha) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let program = self.program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let program = self.program.borrow();
    let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: ColorAlpha) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let program = self.program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<|endoftext|>


<commit_before>// load and store. word, half, byte. normal and wait (dmb) and wait_all (dsb)

fn store_word(addr: u32, val: u32) {
  unsafe {
    asm!("str $0, [$1]"
      :
      : "r"(val), "r"(addr)
      :
      : "volatile"
      );
  }
}

fn store_word_wait(addr: u32, val: u32) {
  unsafe {
    asm!("str $0, [$1]\n\t
          dmb"
      :
      : "r"(val), "r"(addr)
      :
      : "volatile"
      );
  }
}

fn store_word_wait_all(addr: u32, val: u32) {
  unsafe {
    asm!("str $0, [$1]\n\t
          dsb"
      :
      : "r"(val), "r"(addr)
      :
      : "volatile"
      );
  }
}
<commit_msg>public function<commit_after>// load and store. word, half, byte. normal and wait (dmb) and wait_all (dsb)

pub fn store_word(addr: u32, val: u32) {
  unsafe {
    asm!("str $0, [$1]"
      :
      : "r"(val), "r"(addr)
      :
      : "volatile"
      );
  }
}

pub fn store_word_wait(addr: u32, val: u32) {
  unsafe {
    asm!("str $0, [$1]\n\t
          dmb"
      :
      : "r"(val), "r"(addr)
      :
      : "volatile"
      );
  }
}

pub fn store_word_wait_all(addr: u32, val: u32) {
  unsafe {
    asm!("str $0, [$1]\n\t
          dsb"
      :
      : "r"(val), "r"(addr)
      :
      : "volatile"
      );
  }
}
<|endoftext|>


<commit_before>use self::super::{Status, MAP};
use self::super::super::http;

pub fn close(ctn: u16) -> Status {
    // Do we know this CTN?
    if !MAP.lock().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return Status::ErrInvalid;
    }

    let pn = MAP.lock().get(&ctn).unwrap().clone();
    let path = format!("ct_close/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => match res.status {
            200 => handle_ok_status(res.body, ctn),
            _ => {
                error!("Request failed! Server response was not OK!");
                return Status::ErrHtsi;
            }
        },
    }
}

fn handle_ok_status(body: String, ctn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            return Status::ErrHtsi;
        }
    };

    match status {
        Status::OK => {
            // Remove CTN
            MAP.lock().remove(&ctn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::close;
    use super::super::MAP;
    use rand;
    use rouille::Response;

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn))
    }

    #[test]
    fn returns_err_invalid_if_already_closed() {
        let ctn = rand::random::<u16>();

        assert_eq!(-1, close(ctn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        let shutdown = test_server!((request: &Request) {
            assert_eq!(request.url(), format!("/ct_close/{}/{}", ctn, pn));

            Response::empty_404()
        });

        close(ctn);

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        let shutdown = test_server!((request: &Request) {
            Response::empty_404()
        });

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        let shutdown = test_server!((request: &Request) {
            Response::text("hello world")
        });

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_response_status_from_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        let shutdown = test_server!((request: &Request) {
            Response::text("-11")
        });

        assert_eq!(-11, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn return_ok_and_close_ctn_if_server_returns_ok() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        let shutdown = test_server!((request: &Request) {
            Response::text("0")
        });

        assert_eq!(0, close(ctn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }
}
<commit_msg>use test-server for testing ct_close<commit_after>use self::super::{Status, MAP};
use self::super::super::http;

pub fn close(ctn: u16) -> Status {
    // Do we know this CTN?
    if !MAP.lock().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return Status::ErrInvalid;
    }

    let pn = MAP.lock().get(&ctn).unwrap().clone();
    let path = format!("ct_close/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => match res.status {
            200 => handle_ok_status(res.body, ctn),
            _ => {
                error!("Request failed! Server response was not OK!");
                return Status::ErrHtsi;
            }
        },
    }
}

fn handle_ok_status(body: String, ctn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            return Status::ErrHtsi;
        }
    };

    match status {
        Status::OK => {
            // Remove CTN
            MAP.lock().remove(&ctn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::close;
    use super::super::MAP;
    use rand;
    use std::env;
    use test_server::{self, hyper};

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn))
    }

    #[test]
    fn returns_err_invalid_if_already_closed() {
        let ctn = rand::random::<u16>();

        assert_eq!(-1, close(ctn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        close(ctn);

        let (_method, uri, _version, _headers, _body) = server.request().unwrap().deconstruct();

        assert_eq!(format!("/ct_close/{}/{}", ctn, pn), uri.path());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("hello world");
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_response_status_from_server() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("-11");
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-11, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn return_ok_and_close_ctn_if_server_returns_ok() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("0");
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(0, close(ctn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::fmt;

use log::trace;

use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span};

use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(Option<String>),
    UnsupportedInIsolation(String),
    ExperimentalUb { msg: String, url: String },
    Deadlock,
}

impl fmt::Display for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) =>
                write!(f, "the evaluated program completed with exit code {}", code),
            Abort(None) =>
                write!(f, "the evaluated program aborted execution"),
            Abort(Some(msg)) =>
                write!(f, "the evaluated program aborted execution: {}", msg),
            UnsupportedInIsolation(msg) =>
                write!(f, "{}", msg),
            ExperimentalUb { msg, .. } =>
                write!(f, "{}", msg),
            Deadlock =>
                write!(f, "the evaluated program deadlocked"),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    PoppedPointerTag(Item),
    CreatedCallId(CallId),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) =>
                    "abnormal termination",
                UnsupportedInIsolation(_) =>
                    "unsupported operation",
                ExperimentalUb { .. } =>
                    "Undefined Behavior",
                Deadlock => "deadlock",
            };
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
                ExperimentalUb { url, .. } =>
                    vec![
                        format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
                        format!("see {} for further information", url),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            let title = match e.kind {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                _ =>
                    bug!("This error should be impossible in Miri: {}", e),
            };
            let helps = match e.kind {
                Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
                    vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
                Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
                    panic!("Error should never be raised by Miri: {:?}", e.kind),
                Unsupported(_) =>
                    vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) =>
                    vec![
                        format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
                        format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
                        format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
                        format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
    };

    e.print_backtrace();
    let msg = e.to_string();
    report_msg(*ecx.tcx, /*error*/true, &format!("{}: {}", title, msg), msg, helps, &ecx.generate_stacktrace());

    // Debug-dump all locals.
    for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }

    // Extra output to help debug specific issues.
    match e.kind {
        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => {
            eprintln!(
                "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
                access.uninit_ptr.offset.bytes(),
                access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(),
            );
            ecx.memory.dump_alloc(access.uninit_ptr.alloc_id);
            eprintln!();
        }
        _ => {}
    }

    None
}

/// Report an error or note (depending on the `error` argument) with the given stacktrace.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx>(
    tcx: TyCtxt<'tcx>,
    error: bool,
    title: &str,
    span_msg: String,
    mut helps: Vec<String>,
    stacktrace: &[FrameInfo<'tcx>],
) {
    let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
    let mut err = if error {
        tcx.sess.struct_span_err(span, title)
    } else {
        tcx.sess.diagnostic().span_note_diag(span, title)
    };
    // Show main message.
    if span != DUMMY_SP {
        err.span_label(span, span_msg);
    } else {
        // Make sure we show the message even when it is a dummy span.
        err.note(&span_msg);
        err.note("(no span available)");
    }
    // Show help messages.
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().push_str("\n");
        for help in helps {
            err.help(&help);
        }
    }
    // Add backtrace
    for (idx, frame_info) in stacktrace.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

/// Remember enough about the topmost frame so that we can restore the stack
/// after a step was taken.
pub struct TopFrameInfo<'tcx> {
    stack_size: usize,
    instance: Option<ty::Instance<'tcx>>,
    span: Span,
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> {
        // Ensure we have no lingering diagnostics.
        DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));

        let this = self.eval_context_ref();
        if this.active_thread_stack().is_empty() {
            // Diagnostics can happen even with the emoty stack (e.g. deallocation thread-local statics).
            return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
        }
        let frame = this.frame();

        TopFrameInfo {
            stack_size: this.active_thread_stack().len(),
            instance: Some(frame.instance),
            span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span),
        }
    }

    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            let mut diagnostics = diagnostics.borrow_mut();
            if diagnostics.is_empty() {
                return;
            }
            // We need to fix up the stack trace, because the machine has already
            // stepped to the next statement.
            let mut stacktrace = this.generate_stacktrace();
            // Remove newly pushed frames.
            while stacktrace.len() > info.stack_size {
                stacktrace.remove(0);
            }
            // Add popped frame back.
            if stacktrace.len() < info.stack_size {
                assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once");
                let frame_info = FrameInfo {
                    instance: info.instance.unwrap(),
                    span: info.span,
                    lint_root: None,
                };
                stacktrace.insert(0, frame_info);
            } else if let Some(instance) = info.instance {
                // Adjust topmost frame.
                stacktrace[0].span = info.span;
                assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step");
            }

            // Show diagnostics.
            for e in diagnostics.drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    PoppedPointerTag(item) =>
                        format!("popped tracked tag for item {:?}", item),
                    CreatedCallId(id) =>
                        format!("function call with id {}", id),
                    CreatedAlloc(AllocId(id)) =>
                        format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) =>
                        format!("freed allocation with id {}", id),
                };
                report_msg(*this.tcx, /*error*/false, "tracking was triggered", msg, vec![], &stacktrace);
            }
        });
    }
}
<commit_msg>Typos<commit_after>use std::cell::RefCell;
use std::fmt;

use log::trace;

use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span};

use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(Option<String>),
    UnsupportedInIsolation(String),
    ExperimentalUb { msg: String, url: String },
    Deadlock,
}

impl fmt::Display for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) =>
                write!(f, "the evaluated program completed with exit code {}", code),
            Abort(None) =>
                write!(f, "the evaluated program aborted execution"),
            Abort(Some(msg)) =>
                write!(f, "the evaluated program aborted execution: {}", msg),
            UnsupportedInIsolation(msg) =>
                write!(f, "{}", msg),
            ExperimentalUb { msg, .. } =>
                write!(f, "{}", msg),
            Deadlock =>
                write!(f, "the evaluated program deadlocked"),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    PoppedPointerTag(Item),
    CreatedCallId(CallId),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) =>
                    "abnormal termination",
                UnsupportedInIsolation(_) =>
                    "unsupported operation",
                ExperimentalUb { .. } =>
                    "Undefined Behavior",
                Deadlock => "deadlock",
            };
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
                ExperimentalUb { url, .. } =>
                    vec![
                        format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
                        format!("see {} for further information", url),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            let title = match e.kind {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                _ =>
                    bug!("This error should be impossible in Miri: {}", e),
            };
            let helps = match e.kind {
                Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
                    vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
                Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
                    panic!("Error should never be raised by Miri: {:?}", e.kind),
                Unsupported(_) =>
                    vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) =>
                    vec![
                        format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
                        format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
                        format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
                        format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
    };

    e.print_backtrace();
    let msg = e.to_string();
    report_msg(*ecx.tcx, /*error*/true, &format!("{}: {}", title, msg), msg, helps, &ecx.generate_stacktrace());

    // Debug-dump all locals.
    for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }

    // Extra output to help debug specific issues.
    match e.kind {
        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => {
            eprintln!(
                "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
                access.uninit_ptr.offset.bytes(),
                access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(),
            );
            ecx.memory.dump_alloc(access.uninit_ptr.alloc_id);
            eprintln!();
        }
        _ => {}
    }

    None
}

/// Report an error or note (depending on the `error` argument) with the given stacktrace.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx>(
    tcx: TyCtxt<'tcx>,
    error: bool,
    title: &str,
    span_msg: String,
    mut helps: Vec<String>,
    stacktrace: &[FrameInfo<'tcx>],
) {
    let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
    let mut err = if error {
        tcx.sess.struct_span_err(span, title)
    } else {
        tcx.sess.diagnostic().span_note_diag(span, title)
    };
    // Show main message.
    if span != DUMMY_SP {
        err.span_label(span, span_msg);
    } else {
        // Make sure we show the message even when it is a dummy span.
        err.note(&span_msg);
        err.note("(no span available)");
    }
    // Show help messages.
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().push_str("\n");
        for help in helps {
            err.help(&help);
        }
    }
    // Add backtrace
    for (idx, frame_info) in stacktrace.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

/// Remember enough about the topmost frame so that we can restore the stack
/// after a step was taken.
pub struct TopFrameInfo<'tcx> {
    stack_size: usize,
    instance: Option<ty::Instance<'tcx>>,
    span: Span,
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> {
        // Ensure we have no lingering diagnostics.
        DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));

        let this = self.eval_context_ref();
        if this.active_thread_stack().is_empty() {
            // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics).
            return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
        }
        let frame = this.frame();

        TopFrameInfo {
            stack_size: this.active_thread_stack().len(),
            instance: Some(frame.instance),
            span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span),
        }
    }

    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            let mut diagnostics = diagnostics.borrow_mut();
            if diagnostics.is_empty() {
                return;
            }
            // We need to fix up the stack trace, because the machine has already
            // stepped to the next statement.
            let mut stacktrace = this.generate_stacktrace();
            // Remove newly pushed frames.
            while stacktrace.len() > info.stack_size {
                stacktrace.remove(0);
            }
            // Add popped frame back.
            if stacktrace.len() < info.stack_size {
                assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once");
                let frame_info = FrameInfo {
                    instance: info.instance.unwrap(),
                    span: info.span,
                    lint_root: None,
                };
                stacktrace.insert(0, frame_info);
            } else if let Some(instance) = info.instance {
                // Adjust topmost frame.
                stacktrace[0].span = info.span;
                assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step");
            }

            // Show diagnostics.
            for e in diagnostics.drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    PoppedPointerTag(item) =>
                        format!("popped tracked tag for item {:?}", item),
                    CreatedCallId(id) =>
                        format!("function call with id {}", id),
                    CreatedAlloc(AllocId(id)) =>
                        format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) =>
                        format!("freed allocation with id {}", id),
                };
                report_msg(*this.tcx, /*error*/false, "tracking was triggered", msg, vec![], &stacktrace);
            }
        });
    }
}
<|endoftext|>