<commit_before>//! Mouse and key events.

use std::io::{Error, ErrorKind};
use std::ascii::AsciiExt;
use std::str;

/// An event reported by the terminal.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Event {
    /// A key press.
    Key(Key),
    /// A mouse button press, release or wheel use at specific coordinates.
    Mouse(MouseEvent),
    /// An event that cannot currently be evaluated.
    Unsupported,
}

/// A mouse related event.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseEvent {
    /// A mouse button was pressed.
    ///
    /// The coordinates are one-based.
    Press(MouseButton, u16, u16),
    /// A mouse button was released.
    ///
    /// The coordinates are one-based.
    Release(u16, u16),
    /// A mouse button is held over the given coordinates.
    ///
    /// The coordinates are one-based.
    Hold(u16, u16),
}

/// A mouse button.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
    /// The left mouse button.
    Left,
    /// The right mouse button.
    Right,
    /// The middle mouse button.
    Middle,
    /// Mouse wheel is going up.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelUp,
    /// Mouse wheel is going down.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelDown,
}

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Null byte.
    Null,
    /// Esc key.
    Esc,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: Result<u8, Error>, iter: &mut I) -> Result<Event, Error>
where I: Iterator<Item = Result<u8, Error>>
{
    let error = Err(Error::new(ErrorKind::Other, "Could not parse an event"));
    match item {
        Ok(b'\x1B') => {
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return error,
                    }
                }
                Some(Ok(b'[')) => {
                    match iter.next() {
                        Some(Ok(b'D')) => Event::Key(Key::Left),
                        Some(Ok(b'C')) => Event::Key(Key::Right),
                        Some(Ok(b'A')) => Event::Key(Key::Up),
                        Some(Ok(b'B')) => Event::Key(Key::Down),
                        Some(Ok(b'H')) => Event::Key(Key::Home),
                        Some(Ok(b'F')) => Event::Key(Key::End),
                        Some(Ok(b'M')) => {
                            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
                            let cb = iter.next().unwrap().unwrap() as i8 - 32;
                            // (1, 1) are the coords for upper left.
                            let cx = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            let cy = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            Event::Mouse(match cb & 0b11 {
                                0 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Left, cx, cy)
                                    }
                                }
                                1 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Middle, cx, cy)
                                    }
                                }
                                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                3 => MouseEvent::Release(cx, cy),
                                _ => return error,
                            })
                        },
                        Some(Ok(b'<')) => {
                            // xterm mouse encoding:
                            // ESC [ < Cb ; Cx ; Cy ; (M or m)
                            let mut buf = Vec::new();
                            let mut c = iter.next().unwrap().unwrap();
                                while match c {
                                    b'm' | b'M' => false,
                                    _ => true,
                                } {
                                    buf.push(c);
                                    c = iter.next().unwrap().unwrap();
                                }
                            let str_buf = String::from_utf8(buf).unwrap();
                            let nums = &mut str_buf.split(';');

                            let cb = nums.next().unwrap().parse::<u16>().unwrap();
                            let cx = nums.next().unwrap().parse::<u16>().unwrap();
                            let cy = nums.next().unwrap().parse::<u16>().unwrap();

                            let event = match cb {
                                0...2 | 64...65 => {
                                    let button = match cb {
                                        0 => MouseButton::Left,
                                        1 => MouseButton::Middle,
                                        2 => MouseButton::Right,
                                        64 => MouseButton::WheelUp,
                                        65 => MouseButton::WheelDown,
                                        _ => return error,
                                    };
                                    match c {
                                        b'M' => MouseEvent::Press(button, cx, cy),
                                        b'm' => MouseEvent::Release(cx, cy),
                                        _ => return error,
                                    }
                                }
                                32 => MouseEvent::Hold(cx, cy),
                                _ => return error,
                            };

                            Event::Mouse(event)
                        },
                        Some(Ok(c @ b'0'...b'9')) => {
                            // Numbered escape code.
                            let mut buf = Vec::new();
                            buf.push(c);
                            let mut c = iter.next().unwrap().unwrap();
                            while match c {
                                b'M' | b'~' => false,
                                _ => true,
                            } {
                                buf.push(c);
                                c = iter.next().unwrap().unwrap();
                            }

                            match c {
                                // rxvt mouse encoding:
                                // ESC [ Cb ; Cx ; Cy ; M
                                b'M' => {
                                    let str_buf = String::from_utf8(buf).unwrap();
                                    let nums = &mut str_buf.split(';');

                                    let cb = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cx = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cy = nums.next().unwrap().parse::<u16>().unwrap();

                                    let event = match cb {
                                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
                                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
                                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                        35 => MouseEvent::Release(cx, cy),
                                        64 => MouseEvent::Hold(cx, cy),
                                        96 |
                                        97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
                                        _ => return error,
                                    };

                                    Event::Mouse(event)
                                },
                                // Special key code.
                                b'~' => {
                                    let num: u8 = String::from_utf8(buf).unwrap().parse().unwrap();
                                    match num {
                                        1 | 7 => Event::Key(Key::Home),
                                        2 => Event::Key(Key::Insert),
                                        3 => Event::Key(Key::Delete),
                                        4 | 8 => Event::Key(Key::End),
                                        5 => Event::Key(Key::PageUp),
                                        6 => Event::Key(Key::PageDown),
                                        v @ 11...15 => Event::Key(Key::F(v - 10)),
                                        v @ 17...21 => Event::Key(Key::F(v - 11)),
                                        v @ 23...24 => Event::Key(Key::F(v - 12)),
                                        _ => return error,
                                    }
                                },
                                _ => return error,
                            }
                        },
                        _ => return error,
                    }
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter);
                    Event::Key(Key::Alt(try!(ch)))
                }
                Some(Err(_)) | None => return error,
            })
        }
        Ok(b'\n') | Ok(b'\r') => Ok(Event::Key(Key::Char('\n'))),
        Ok(b'\t') => Ok(Event::Key(Key::Char('\t'))),
        Ok(b'\x7F') => Ok(Event::Key(Key::Backspace)),
        Ok(c @ b'\x01'...b'\x1A') => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        Ok(c @ b'\x1C'...b'\x1F') => {
            Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char)))
        }
        Ok(b'\0') => Ok(Event::Key(Key::Null)),
        Ok(c) => {
            Ok({
                let ch = parse_utf8_char(c, iter);
                Event::Key(Key::Char(try!(ch)))
            })
        }
        Err(e) => Err(e),
    }
}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
    where I: Iterator<Item = Result<u8, Error>> {
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap())
            }
            if bytes.len() >= 4 { return error; }
        }
    }
}

#[cfg(test)]
#[test]
fn test_parse_utf8() {
    let st = "abcéŷ¤£€ù%323";
    let ref mut bytes = st.bytes().map(|x| Ok(x));
    let chars = st.chars();
    for c in chars {
        let b = bytes.next().unwrap().unwrap();
        assert!(c == parse_utf8_char(b, bytes).unwrap());
    }
}
<commit_msg>Fix CSI sequence detection (#69)<commit_after>//! Mouse and key events.

use std::io::{Error, ErrorKind};
use std::ascii::AsciiExt;
use std::str;

/// An event reported by the terminal.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Event {
    /// A key press.
    Key(Key),
    /// A mouse button press, release or wheel use at specific coordinates.
    Mouse(MouseEvent),
    /// An event that cannot currently be evaluated.
    Unsupported,
}

/// A mouse related event.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseEvent {
    /// A mouse button was pressed.
    ///
    /// The coordinates are one-based.
    Press(MouseButton, u16, u16),
    /// A mouse button was released.
    ///
    /// The coordinates are one-based.
    Release(u16, u16),
    /// A mouse button is held over the given coordinates.
    ///
    /// The coordinates are one-based.
    Hold(u16, u16),
}

/// A mouse button.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
    /// The left mouse button.
    Left,
    /// The right mouse button.
    Right,
    /// The middle mouse button.
    Middle,
    /// Mouse wheel is going up.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelUp,
    /// Mouse wheel is going down.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelDown,
}

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Null byte.
    Null,
    /// Esc key.
    Esc,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: Result<u8, Error>, iter: &mut I) -> Result<Event, Error>
where I: Iterator<Item = Result<u8, Error>>
{
    let error = Err(Error::new(ErrorKind::Other, "Could not parse an event"));
    match item {
        Ok(b'\x1B') => {
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return error,
                    }
                }
                Some(Ok(b'[')) => {
                    match iter.next() {
                        Some(Ok(b'D')) => Event::Key(Key::Left),
                        Some(Ok(b'C')) => Event::Key(Key::Right),
                        Some(Ok(b'A')) => Event::Key(Key::Up),
                        Some(Ok(b'B')) => Event::Key(Key::Down),
                        Some(Ok(b'H')) => Event::Key(Key::Home),
                        Some(Ok(b'F')) => Event::Key(Key::End),
                        Some(Ok(b'M')) => {
                            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
                            let cb = iter.next().unwrap().unwrap() as i8 - 32;
                            // (1, 1) are the coords for upper left.
                            let cx = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            let cy = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            Event::Mouse(match cb & 0b11 {
                                0 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Left, cx, cy)
                                    }
                                }
                                1 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Middle, cx, cy)
                                    }
                                }
                                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                3 => MouseEvent::Release(cx, cy),
                                _ => return error,
                            })
                        },
                        Some(Ok(b'<')) => {
                            // xterm mouse encoding:
                            // ESC [ < Cb ; Cx ; Cy ; (M or m)
                            let mut buf = Vec::new();
                            let mut c = iter.next().unwrap().unwrap();
                                while match c {
                                    b'm' | b'M' => false,
                                    _ => true,
                                } {
                                    buf.push(c);
                                    c = iter.next().unwrap().unwrap();
                                }
                            let str_buf = String::from_utf8(buf).unwrap();
                            let nums = &mut str_buf.split(';');

                            let cb = nums.next().unwrap().parse::<u16>().unwrap();
                            let cx = nums.next().unwrap().parse::<u16>().unwrap();
                            let cy = nums.next().unwrap().parse::<u16>().unwrap();

                            let event = match cb {
                                0...2 | 64...65 => {
                                    let button = match cb {
                                        0 => MouseButton::Left,
                                        1 => MouseButton::Middle,
                                        2 => MouseButton::Right,
                                        64 => MouseButton::WheelUp,
                                        65 => MouseButton::WheelDown,
                                        _ => return error,
                                    };
                                    match c {
                                        b'M' => MouseEvent::Press(button, cx, cy),
                                        b'm' => MouseEvent::Release(cx, cy),
                                        _ => return error,
                                    }
                                }
                                32 => MouseEvent::Hold(cx, cy),
                                _ => return error,
                            };

                            Event::Mouse(event)
                        },
                        Some(Ok(c @ b'0'...b'9')) => {
                            // Numbered escape code.
                            let mut buf = Vec::new();
                            buf.push(c);
                            let mut c = iter.next().unwrap().unwrap();
                            // The final byte of a CSI sequence can be in the range 64-126
                            // So let's keep reading anything else.
                            while c < 64 || c > 126 {
                                buf.push(c);
                                c = iter.next().unwrap().unwrap();
                            }

                            match c {
                                // rxvt mouse encoding:
                                // ESC [ Cb ; Cx ; Cy ; M
                                b'M' => {
                                    let str_buf = String::from_utf8(buf).unwrap();
                                    let nums = &mut str_buf.split(';');

                                    let cb = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cx = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cy = nums.next().unwrap().parse::<u16>().unwrap();

                                    let event = match cb {
                                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
                                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
                                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                        35 => MouseEvent::Release(cx, cy),
                                        64 => MouseEvent::Hold(cx, cy),
                                        96 |
                                        97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
                                        _ => return error,
                                    };

                                    Event::Mouse(event)
                                },
                                // Special key code.
                                b'~' => {
                                    let num: u8 = String::from_utf8(buf).unwrap().parse().unwrap();
                                    match num {
                                        1 | 7 => Event::Key(Key::Home),
                                        2 => Event::Key(Key::Insert),
                                        3 => Event::Key(Key::Delete),
                                        4 | 8 => Event::Key(Key::End),
                                        5 => Event::Key(Key::PageUp),
                                        6 => Event::Key(Key::PageDown),
                                        v @ 11...15 => Event::Key(Key::F(v - 10)),
                                        v @ 17...21 => Event::Key(Key::F(v - 11)),
                                        v @ 23...24 => Event::Key(Key::F(v - 12)),
                                        _ => return error,
                                    }
                                },
                                _ => return error,
                            }
                        },
                        _ => return error,
                    }
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter);
                    Event::Key(Key::Alt(try!(ch)))
                }
                Some(Err(_)) | None => return error,
            })
        }
        Ok(b'\n') | Ok(b'\r') => Ok(Event::Key(Key::Char('\n'))),
        Ok(b'\t') => Ok(Event::Key(Key::Char('\t'))),
        Ok(b'\x7F') => Ok(Event::Key(Key::Backspace)),
        Ok(c @ b'\x01'...b'\x1A') => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        Ok(c @ b'\x1C'...b'\x1F') => {
            Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char)))
        }
        Ok(b'\0') => Ok(Event::Key(Key::Null)),
        Ok(c) => {
            Ok({
                let ch = parse_utf8_char(c, iter);
                Event::Key(Key::Char(try!(ch)))
            })
        }
        Err(e) => Err(e),
    }
}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
    where I: Iterator<Item = Result<u8, Error>> {
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap())
            }
            if bytes.len() >= 4 { return error; }
        }
    }
}

#[cfg(test)]
#[test]
fn test_parse_utf8() {
    let st = "abcéŷ¤£€ù%323";
    let ref mut bytes = st.bytes().map(|x| Ok(x));
    let chars = st.chars();
    for c in chars {
        let b = bytes.next().unwrap().unwrap();
        assert!(c == parse_utf8_char(b, bytes).unwrap());
    }
}
<|endoftext|>


<commit_before>use std::convert::From;

use ::{Player, WIDTH, HEIGHT};
use unit::{Unit, PovUnit, GeneralUnit};
use move_conditions::{ALL_DIRECTIONS, Move, MoveCondition};

#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Field<T: Unit> {
    pub rows: [[Option<T>; WIDTH]; HEIGHT],
}

impl<T: Unit> Field<T> {
    pub fn new() -> Field<T> {
        let rows = [[None; WIDTH]; HEIGHT];
        Field {
            rows: rows,
        }
    }

    pub fn possible_moves(&self, player: Player, move_condition: &MoveCondition) -> Vec<Move> {
        let mut res = Vec::new();

        for (j, row) in self.rows.iter().enumerate() {
            for (i, _) in row.iter().enumerate().filter(|&(_, x)| {if let &Some(x) = x {x.owner() == player} else {false} }) {
                for direction in ALL_DIRECTIONS {
                    let movement = Move {from: (i, j), direction: *direction};
                    if move_condition.is_valid(movement) { res.push(movement); }
                }
            }
        }

        res
    }
}

#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct PovField {
    pub pov: Player,
    pub field: Field<PovUnit>,
}

impl<'a> From<(&'a Field<GeneralUnit>, Player)> for PovField {
    fn from( data: (&Field<GeneralUnit>, Player) ) -> PovField {
        let (ref field, player) = data;
        let mut rows = [[None; WIDTH]; HEIGHT];

        for (i, ref row) in field.rows.iter().enumerate() {
            for (j, unit) in row.iter().enumerate() {
                if let Some(unit) = *unit {
                    rows[i][j] = Some( PovUnit::from( (unit, player) ) );
                }
            }
        }

        PovField {
            pov: player,
            field: Field{ rows: rows },
        }
    }
}

#[test]
fn possible_moves_test() {
    use move_conditions::{Direction, OnlyForwardMove};
    use ::RPS;

    let mut field = Field::new();
    let move_condition = OnlyForwardMove;
    field.rows[0][0] = Some(GeneralUnit { rps: RPS::Rock, owner: Player::Blue, visible: false,});
    field.rows[0][1] = Some(GeneralUnit { rps: RPS::Rock, owner: Player::Red, visible: false,});
    field.rows[1][0] = Some(GeneralUnit { rps: RPS::Rock, owner: Player::Red, visible: false,});
    let moves = vec![Move {from: (1, 0), direction: Direction::Forward},
                     Move {from: (0, 1), direction: Direction::Forward}];
    assert_eq!(field.possible_moves(Player::Red, &move_condition), moves);
}
<commit_msg>Added impl possible_moves for PovField<commit_after>use std::convert::From;

use ::{Player, WIDTH, HEIGHT};
use unit::{Unit, PovUnit, GeneralUnit};
use move_conditions::{ALL_DIRECTIONS, Move, MoveCondition, OnlyForwardMove};

#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Field<T: Unit> {
    pub rows: [[Option<T>; WIDTH]; HEIGHT],
}

impl<T: Unit> Field<T> {
    pub fn new() -> Field<T> {
        let rows = [[None; WIDTH]; HEIGHT];
        Field {
            rows: rows,
        }
    }

    pub fn possible_moves(&self, player: Player, move_condition: &MoveCondition) -> Vec<Move> {
        let mut res = Vec::new();

        for (j, row) in self.rows.iter().enumerate() {
            for (i, _) in row.iter().enumerate().filter(|&(_, x)| {if let &Some(x) = x {x.owner() == player} else {false} }) {
                for direction in ALL_DIRECTIONS {
                    let movement = Move {from: (i, j), direction: *direction};
                    if move_condition.is_valid(movement) { res.push(movement); }
                }
            }
        }

        res
    }
}

#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct PovField {
    pub pov: Player,
    pub field: Field<PovUnit>,
}

impl PovField {
    pub fn possible_moves(&self) -> Vec<Move> {
        self.field.possible_moves(self.pov, &OnlyForwardMove)
    }
}

impl<'a> From<(&'a Field<GeneralUnit>, Player)> for PovField {
    fn from( data: (&Field<GeneralUnit>, Player) ) -> PovField {
        let (ref field, player) = data;
        let mut rows = [[None; WIDTH]; HEIGHT];

        for (i, ref row) in field.rows.iter().enumerate() {
            for (j, unit) in row.iter().enumerate() {
                if let Some(unit) = *unit {
                    rows[i][j] = Some( PovUnit::from( (unit, player) ) );
                }
            }
        }

        PovField {
            pov: player,
            field: Field{ rows: rows },
        }
    }
}

#[test]
fn possible_moves_test() {
    use move_conditions::{Direction, OnlyForwardMove};
    use ::RPS;

    let mut field = Field::new();
    let move_condition = OnlyForwardMove;
    field.rows[0][0] = Some(GeneralUnit { rps: RPS::Rock, owner: Player::Blue, visible: false,});
    field.rows[0][1] = Some(GeneralUnit { rps: RPS::Rock, owner: Player::Red, visible: false,});
    field.rows[1][0] = Some(GeneralUnit { rps: RPS::Rock, owner: Player::Red, visible: false,});
    let moves = vec![Move {from: (1, 0), direction: Direction::Forward},
                     Move {from: (0, 1), direction: Direction::Forward}];
    assert_eq!(field.possible_moves(Player::Red, &move_condition), moves);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Ben Ashford
 *
 * 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.
 */

//! Geo queries

use serde::ser::{Serialize, Serializer, SerializeMap};

use ::json::{MergeSerialize, NoOuter, ShouldSkip};
use ::units::{Distance, DistanceType, GeoBox, Location};

use super::Query;
use super::common::FieldBasedQuery;

#[derive(Debug, Serialize)]
pub enum ShapeOption {
    #[serde(rename="shape")]
    Shape(Shape),
    #[serde(rename="indexed_shape")]
    IndexedShape(IndexedShape)
}

from!(Shape, ShapeOption, Shape);
from!(IndexedShape, ShapeOption, IndexedShape);

/// GeoShape query
#[derive(Debug, Serialize)]
pub struct GeoShapeQuery(FieldBasedQuery<Option<ShapeOption>, NoOuter>);

impl Query {
    pub fn build_geo_shape<A>(field: A) -> GeoShapeQuery
        where A: Into<String> {

        GeoShapeQuery(FieldBasedQuery::new(field.into(), None, NoOuter))
    }
}

impl GeoShapeQuery {
    pub fn with_shape<A>(mut self, shape: A) -> Self
        where A: Into<Shape> {

        self.0.inner = Some(ShapeOption::Shape(shape.into()));
        self
    }

    pub fn with_indexed_shape<A>(mut self, indexed_shape: A) -> Self
        where A: Into<IndexedShape> {

        self.0.inner = Some(ShapeOption::IndexedShape(indexed_shape.into()));
        self
    }

    build!(GeoShape);
}

// Required for GeoShape
#[derive(Debug, Serialize)]
pub struct Shape {
    #[serde(rename="type")]
    shape_type: String,
    coordinates: Vec<(f64, f64)>
}

impl Shape {
    pub fn new<A: Into<String>>(shape_type: A, coordinates: Vec<(f64, f64)>) -> Shape {
        Shape {
            shape_type:  shape_type.into(),
            coordinates: coordinates
        }
    }
}

#[derive(Debug, Serialize)]
pub struct IndexedShape {
    id:       String,
    doc_type: String,
    index:    String,
    path:     String
}

impl IndexedShape {
    pub fn new<A, B, C, D>(id: A, doc_type: B, index: C, path: D) -> IndexedShape
        where A: Into<String>,
              B: Into<String>,
              C: Into<String>,
              D: Into<String> {
        IndexedShape {
            id: id.into(),
            doc_type: doc_type.into(),
            index: index.into(),
            path: path.into()
        }
    }
}

/// Geo Bounding Box Query
#[derive(Debug, Serialize)]
pub struct GeoBoundingBoxQuery(FieldBasedQuery<GeoBoundingBoxQueryInner, NoOuter>);

#[derive(Debug, Default, Serialize)]
pub struct GeoBoundingBoxQueryInner {
    geo_box: GeoBox,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    coerce: Option<bool>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    ignore_malformed: Option<bool>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip", rename="type")]
    filter_type: Option<Type>
}

impl Query {
    pub fn build_geo_bounding_box<A, B>(field: A, geo_box: B) -> GeoBoundingBoxQuery
        where A: Into<String>,
              B: Into<GeoBox> {
        GeoBoundingBoxQuery(FieldBasedQuery::new(field.into(),
                                                 GeoBoundingBoxQueryInner {
                                                     geo_box: geo_box.into(),
                                                     ..Default::default()
                                                 },
                                                 NoOuter))
    }
}

impl GeoBoundingBoxQuery {
    add_inner_field!(with_coerce, coerce, bool);
    add_inner_field!(with_ignore_malformed, ignore_malformed, bool);
    add_inner_field!(with_type, filter_type, Type);

    build!(GeoBoundingBox);
}

/// Geo Bounding Box filter type
#[derive(Debug)]
pub enum Type {
    Indexed,
    Memory
}

impl Serialize for Type {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        use self::Type::*;
        match self {
            &Indexed => "indexed",
            &Memory => "memory"
        }.serialize(serializer)
    }
}

/// Geo Distance query
///
/// TODO: Specific full unit test for querying with a generated query from here
#[derive(Debug, Default, Serialize)]
pub struct GeoDistanceQuery {
    field: String,
    location: Location,
    distance: Distance,
    distance_type: Option<DistanceType>,
    optimize_bbox: Option<OptimizeBbox>,
    coerce: Option<bool>,
    ignore_malformed: Option<bool>
}

impl Query {
    pub fn build_geo_distance<A, B, C>(field: A,
                                       location: B,
                                       distance: C) -> GeoDistanceQuery
        where A: Into<String>,
              B: Into<Location>,
              C: Into<Distance> {
        GeoDistanceQuery {
            field: field.into(),
            location: location.into(),
            distance: distance.into(),
            ..Default::default()
        }
    }
}

impl GeoDistanceQuery {
    add_field!(with_distance_type, distance_type, DistanceType);
    add_field!(with_optimize_bbox, optimize_bbox, OptimizeBbox);
    add_field!(with_coerce, coerce, bool);
    add_field!(with_ignore_malformed, ignore_malformed, bool);

    build!(GeoDistance);
}

/// Options for `optimize_bbox`
#[derive(Debug)]
pub enum OptimizeBbox {
    Memory,
    Indexed,
    None
}

impl Serialize for OptimizeBbox {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        use self::OptimizeBbox::*;
        match self {
            &Memory => "memory".serialize(serializer),
            &Indexed => "indexed".serialize(serializer),
            &None => "none".serialize(serializer)
        }
    }
}

/// Geo Polygon query
#[derive(Debug, Serialize)]
pub struct GeoPolygonQuery(FieldBasedQuery<GeoPolygonQueryInner, NoOuter>);

#[derive(Debug, Default, Serialize)]
pub struct GeoPolygonQueryInner {
    points: Vec<Location>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    coerce: Option<bool>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    ignore_malformed: Option<bool>
}

impl Query {
    pub fn build_geo_polygon<A, B>(field: A,
                                   points: B) -> GeoPolygonQuery
        where A: Into<String>,
              B: Into<Vec<Location>> {
        GeoPolygonQuery(FieldBasedQuery::new(field.into(),
                                             GeoPolygonQueryInner {
                                                 points: points.into(),
                                                 ..Default::default()
                                             },
                                             NoOuter))
    }
}

impl GeoPolygonQuery {
    add_inner_field!(with_coerce, coerce, bool);
    add_inner_field!(with_ignore_malformed, ignore_malformed, bool);

    build!(GeoPolygon);
}

/// Geohash cell query
#[derive(Debug, Serialize)]
pub struct GeohashCellQuery(FieldBasedQuery<Location, GeohashCellQueryOuter>);

#[derive(Debug, Default)]
pub struct GeohashCellQueryOuter {
    precision: Option<Precision>,
    neighbors: Option<bool>,
}

impl MergeSerialize for GeohashCellQueryOuter {
    fn merge_serialize<S>(&self,
                          serializer: &mut S) -> Result<(), S::Error>
        where S: SerializeMap {

        match self.precision {
            Some(ref p) => {
                serializer.serialize_entry("precision", p)?;
            },
            None => ()
        };
        match self.neighbors {
            Some(b) => {
                serializer.serialize_entry("neighbors", &b)?;
            },
            None => ()
        }
        Ok(())
    }
}

impl Query {
    pub fn build_geohash_cell<A, B>(field: A, location: B) -> GeohashCellQuery
        where A: Into<String>,
              B: Into<Location> {
        GeohashCellQuery(FieldBasedQuery::new(field.into(),
                                              location.into(),
                                              Default::default()))
    }
}

impl GeohashCellQuery {
    add_outer_field!(with_precision, precision, Precision);
    add_outer_field!(with_neighbors, neighbors, bool);

    build!(GeohashCell);
}

#[derive(Debug)]
pub enum Precision {
    Geohash(u64),
    Distance(Distance)
}

impl Default for Precision {
    fn default() -> Self {
        Precision::Distance(Default::default())
    }
}

from!(u64, Precision, Geohash);
from!(Distance, Precision, Distance);

impl Serialize for Precision {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        use self::Precision::*;
        match self {
            &Geohash(precision) => precision.serialize(serializer),
            &Distance(ref dist) => dist.serialize(serializer)
        }
    }
}
<commit_msg>Fix geo_distance query request generation<commit_after>/*
 * Copyright 2016 Ben Ashford
 *
 * 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.
 */

//! Geo queries

use serde::ser::{Serialize, Serializer, SerializeMap};

use ::json::{MergeSerialize, NoOuter, ShouldSkip};
use ::units::{Distance, DistanceType, GeoBox, Location};

use super::Query;
use super::common::FieldBasedQuery;

#[derive(Debug, Serialize)]
pub enum ShapeOption {
    #[serde(rename="shape")]
    Shape(Shape),
    #[serde(rename="indexed_shape")]
    IndexedShape(IndexedShape)
}

from!(Shape, ShapeOption, Shape);
from!(IndexedShape, ShapeOption, IndexedShape);

/// GeoShape query
#[derive(Debug, Serialize)]
pub struct GeoShapeQuery(FieldBasedQuery<Option<ShapeOption>, NoOuter>);

impl Query {
    pub fn build_geo_shape<A>(field: A) -> GeoShapeQuery
        where A: Into<String> {

        GeoShapeQuery(FieldBasedQuery::new(field.into(), None, NoOuter))
    }
}

impl GeoShapeQuery {
    pub fn with_shape<A>(mut self, shape: A) -> Self
        where A: Into<Shape> {

        self.0.inner = Some(ShapeOption::Shape(shape.into()));
        self
    }

    pub fn with_indexed_shape<A>(mut self, indexed_shape: A) -> Self
        where A: Into<IndexedShape> {

        self.0.inner = Some(ShapeOption::IndexedShape(indexed_shape.into()));
        self
    }

    build!(GeoShape);
}

// Required for GeoShape
#[derive(Debug, Serialize)]
pub struct Shape {
    #[serde(rename="type")]
    shape_type: String,
    coordinates: Vec<(f64, f64)>
}

impl Shape {
    pub fn new<A: Into<String>>(shape_type: A, coordinates: Vec<(f64, f64)>) -> Shape {
        Shape {
            shape_type:  shape_type.into(),
            coordinates: coordinates
        }
    }
}

#[derive(Debug, Serialize)]
pub struct IndexedShape {
    id:       String,
    doc_type: String,
    index:    String,
    path:     String
}

impl IndexedShape {
    pub fn new<A, B, C, D>(id: A, doc_type: B, index: C, path: D) -> IndexedShape
        where A: Into<String>,
              B: Into<String>,
              C: Into<String>,
              D: Into<String> {
        IndexedShape {
            id: id.into(),
            doc_type: doc_type.into(),
            index: index.into(),
            path: path.into()
        }
    }
}

/// Geo Bounding Box Query
#[derive(Debug, Serialize)]
pub struct GeoBoundingBoxQuery(FieldBasedQuery<GeoBoundingBoxQueryInner, NoOuter>);

#[derive(Debug, Default, Serialize)]
pub struct GeoBoundingBoxQueryInner {
    geo_box: GeoBox,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    coerce: Option<bool>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    ignore_malformed: Option<bool>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip", rename="type")]
    filter_type: Option<Type>
}

impl Query {
    pub fn build_geo_bounding_box<A, B>(field: A, geo_box: B) -> GeoBoundingBoxQuery
        where A: Into<String>,
              B: Into<GeoBox> {
        GeoBoundingBoxQuery(FieldBasedQuery::new(field.into(),
                                                 GeoBoundingBoxQueryInner {
                                                     geo_box: geo_box.into(),
                                                     ..Default::default()
                                                 },
                                                 NoOuter))
    }
}

impl GeoBoundingBoxQuery {
    add_inner_field!(with_coerce, coerce, bool);
    add_inner_field!(with_ignore_malformed, ignore_malformed, bool);
    add_inner_field!(with_type, filter_type, Type);

    build!(GeoBoundingBox);
}

/// Geo Bounding Box filter type
#[derive(Debug)]
pub enum Type {
    Indexed,
    Memory
}

impl Serialize for Type {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        use self::Type::*;
        match self {
            &Indexed => "indexed",
            &Memory => "memory"
        }.serialize(serializer)
    }
}

/// Geo Distance query
///
/// TODO: Specific full unit test for querying with a generated query from here
#[derive(Debug, Serialize)]
pub struct GeoDistanceQuery(FieldBasedQuery<Location, GeoDistanceQueryOuter>);

#[derive(Debug, Default)]
struct GeoDistanceQueryOuter {
    distance: Distance,
    distance_type: Option<DistanceType>,
    optimize_bbox: Option<OptimizeBbox>,
    coerce: Option<bool>,
    ignore_malformed: Option<bool>
}

impl MergeSerialize for GeoDistanceQueryOuter {
    fn merge_serialize<S>(&self,
                          serializer: &mut S) -> Result<(), S::Error>
        where S: SerializeMap {

        serializer.serialize_entry("distance", &self.distance)?;
        if let Some(ref t) = self.distance_type {
            serializer.serialize_entry("distance_type", t)?;
        }
        if let Some(ref b) = self.optimize_bbox {
            serializer.serialize_entry("optimize_bbox", b)?;
        }
        if let Some(ref b) = self.coerce {
            serializer.serialize_entry("coerce", b)?;
        }
        if let Some(ref b) = self.ignore_malformed {
            serializer.serialize_entry("ignore_malformed", b)?;
        }
        Ok(())
    }
}

impl Query {
    pub fn build_geo_distance<A, B, C>(field: A,
                                       location: B,
                                       distance: C) -> GeoDistanceQuery
        where A: Into<String>,
              B: Into<Location>,
              C: Into<Distance> {
        let outer = GeoDistanceQueryOuter {
            distance: distance.into(),
            ..Default::default()
        };
        GeoDistanceQuery(FieldBasedQuery::new(field.into(), location.into(), outer))
    }
}

impl GeoDistanceQuery {
    add_outer_field!(with_distance_type, distance_type, DistanceType);
    add_outer_field!(with_optimize_bbox, optimize_bbox, OptimizeBbox);
    add_outer_field!(with_coerce, coerce, bool);
    add_outer_field!(with_ignore_malformed, ignore_malformed, bool);

    build!(GeoDistance);
}

/// Options for `optimize_bbox`
#[derive(Debug)]
pub enum OptimizeBbox {
    Memory,
    Indexed,
    None
}

impl Serialize for OptimizeBbox {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        use self::OptimizeBbox::*;
        match self {
            &Memory => "memory".serialize(serializer),
            &Indexed => "indexed".serialize(serializer),
            &None => "none".serialize(serializer)
        }
    }
}

/// Geo Polygon query
#[derive(Debug, Serialize)]
pub struct GeoPolygonQuery(FieldBasedQuery<GeoPolygonQueryInner, NoOuter>);

#[derive(Debug, Default, Serialize)]
pub struct GeoPolygonQueryInner {
    points: Vec<Location>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    coerce: Option<bool>,
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    ignore_malformed: Option<bool>
}

impl Query {
    pub fn build_geo_polygon<A, B>(field: A,
                                   points: B) -> GeoPolygonQuery
        where A: Into<String>,
              B: Into<Vec<Location>> {
        GeoPolygonQuery(FieldBasedQuery::new(field.into(),
                                             GeoPolygonQueryInner {
                                                 points: points.into(),
                                                 ..Default::default()
                                             },
                                             NoOuter))
    }
}

impl GeoPolygonQuery {
    add_inner_field!(with_coerce, coerce, bool);
    add_inner_field!(with_ignore_malformed, ignore_malformed, bool);

    build!(GeoPolygon);
}

/// Geohash cell query
#[derive(Debug, Serialize)]
pub struct GeohashCellQuery(FieldBasedQuery<Location, GeohashCellQueryOuter>);

#[derive(Debug, Default)]
pub struct GeohashCellQueryOuter {
    precision: Option<Precision>,
    neighbors: Option<bool>,
}

impl MergeSerialize for GeohashCellQueryOuter {
    fn merge_serialize<S>(&self,
                          serializer: &mut S) -> Result<(), S::Error>
        where S: SerializeMap {

        match self.precision {
            Some(ref p) => {
                serializer.serialize_entry("precision", p)?;
            },
            None => ()
        };
        match self.neighbors {
            Some(b) => {
                serializer.serialize_entry("neighbors", &b)?;
            },
            None => ()
        }
        Ok(())
    }
}

impl Query {
    pub fn build_geohash_cell<A, B>(field: A, location: B) -> GeohashCellQuery
        where A: Into<String>,
              B: Into<Location> {
        GeohashCellQuery(FieldBasedQuery::new(field.into(),
                                              location.into(),
                                              Default::default()))
    }
}

impl GeohashCellQuery {
    add_outer_field!(with_precision, precision, Precision);
    add_outer_field!(with_neighbors, neighbors, bool);

    build!(GeohashCell);
}

#[derive(Debug)]
pub enum Precision {
    Geohash(u64),
    Distance(Distance)
}

impl Default for Precision {
    fn default() -> Self {
        Precision::Distance(Default::default())
    }
}

from!(u64, Precision, Geohash);
from!(Distance, Precision, Distance);

impl Serialize for Precision {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        use self::Precision::*;
        match self {
            &Geohash(precision) => precision.serialize(serializer),
            &Distance(ref dist) => dist.serialize(serializer)
        }
    }
}
<|endoftext|>


<commit_before>use super::traits::{EdgeWeight, Edges, Graph};
use closed01::Closed01;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use petgraph::{EdgeDirection, Directed};
use petgraph::Graph as PetGraph;
use std::fmt::Debug;

#[derive(Debug)]
pub struct Edge {
    /// Node index type. Our graphs never exceed 4 billion nodes.
    pointing_node: u32,
    weight: EdgeWeight,
}

impl Edge {
    pub fn new_unweighted(node_idx: usize) -> Edge {
        Edge::new(node_idx, Closed01::zero())
    }

    pub fn new(node_idx: usize, weight: EdgeWeight) -> Edge {
        assert!(node_idx <= u32::max_value() as usize);
        Edge {
            pointing_node: node_idx as u32,
            weight: weight,
        }
    }
}

#[derive(Debug)]
pub struct EdgeList {
    edges: Vec<Edge>,
}

impl EdgeList {
    pub fn new(edges: Vec<Edge>) -> EdgeList {
        EdgeList { edges: edges }
    }
}

impl Edges for EdgeList {
    #[inline]
    fn num_edges(&self) -> usize {
        self.edges.len()
    }

    #[inline]
    fn nth_edge(&self, n: usize) -> Option<usize> {
        self.edges.get(n).map(|n| n.pointing_node as usize)
    }

    #[inline]
    fn nth_edge_weight(&self, n: usize) -> Option<EdgeWeight> {
        self.edges.get(n).map(|n| n.weight)
    }
}

#[derive(Debug)]
pub struct Node<T: Debug + Clone> {
    in_edges: EdgeList,
    out_edges: EdgeList,
    node_value: T,
}

impl<T: Debug + Clone> Node<T> {
    pub fn new(in_edges: EdgeList, out_edges: EdgeList, node_value: T) -> Node<T> {
        Node {
            in_edges: in_edges,
            out_edges: out_edges,
            node_value: node_value,
        }
    }

    pub fn node_value(&self) -> &T {
        &self.node_value
    }

    pub fn add_in_edge(&mut self, edge: Edge) {
        self.in_edges.edges.push(edge);
    }

    pub fn add_out_edge(&mut self, edge: Edge) {
        self.out_edges.edges.push(edge);
    }

    fn degree(&self) -> usize {
        self.in_edges.num_edges() + self.out_edges.num_edges()
    }
}

#[derive(Debug)]
pub struct OwnedGraph<T: Debug + Clone> {
    nodes: Vec<Node<T>>,
}

impl<T: Debug + Clone> OwnedGraph<T> {
    pub fn new(nodes: Vec<Node<T>>) -> OwnedGraph<T> {
        OwnedGraph { nodes: nodes }
    }

    pub fn from_petgraph(pg: &PetGraph<T, (), Directed>, default_node_weight: T) -> OwnedGraph<T> {
        OwnedGraph {
            nodes: pg.node_indices()
                     .map(|i| {
                         Node::new(EdgeList::new(pg.edges_directed(i, EdgeDirection::Incoming)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   EdgeList::new(pg.edges_directed(i, EdgeDirection::Outgoing)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   pg.node_weight(i)
                                     .map(|v| v.clone())
                                     .unwrap_or_else(|| default_node_weight.clone()))
                     })
                     .collect(),
        }
    }

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

    pub fn push_empty_node(&mut self, node_value: T) -> usize {
        let idx = self.nodes.len();
        self.nodes.push(Node::new(EdgeList::new(Vec::new()),
                                  EdgeList::new(Vec::new()),
                                  node_value));
        return idx;
    }
}

impl<T: Debug + Clone> Graph for OwnedGraph<T> {
    type EDGE = EdgeList;
    type NODE = T;
    fn num_nodes(&self) -> usize {
        self.nodes.len()
    }

    #[inline]
    fn node_value(&self, node_idx: usize) -> &Self::NODE {
        self.nodes[node_idx].node_value()
    }

    #[inline]
    fn node_degree(&self, node_idx: usize) -> usize {
        self.nodes[node_idx].degree()
    }

    #[inline]
    fn in_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &&self.nodes[node_idx].in_edges
    }

    #[inline]
    fn out_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &self.nodes[node_idx].out_edges
    }
}

pub struct GraphBuilder<T: Debug + Clone> {
    // maps node_id to index in node_in_edges/node_out_edges.
    node_map: BTreeMap<usize, usize>,
    graph: OwnedGraph<T>,
}

impl<T: Debug + Clone> GraphBuilder<T> {
    pub fn new() -> GraphBuilder<T> {
        GraphBuilder {
            node_map: BTreeMap::new(),
            graph: OwnedGraph::new(Vec::new()),
        }
    }

    pub fn graph(self) -> OwnedGraph<T> {
        self.graph
    }

    /// Panics if `node_id` already exists.
    pub fn add_node(&mut self, node_id: usize, node_value: T) -> usize {
        match self.node_map.entry(node_id) {
            Entry::Vacant(e) => {
                let next_id = self.graph.push_empty_node(node_value);
                e.insert(next_id);
                return next_id;
            }
            Entry::Occupied(_) => {
                panic!();
            }
        }
    }

    pub fn add_edge_unweighted(&mut self, source_node_id: usize, target_node_id: usize) {
        self.add_edge(source_node_id, target_node_id, Closed01::zero());
    }

    pub fn add_edge(&mut self, source_node_id: usize, target_node_id: usize, weight: EdgeWeight) {
        let source_index = *self.node_map.get(&source_node_id).unwrap();
        let target_index = *self.node_map.get(&target_node_id).unwrap();
        self.graph.nodes[source_index].add_out_edge(Edge::new(target_index, weight));
        self.graph.nodes[target_index].add_in_edge(Edge::new(source_index, weight));
    }
}
<commit_msg>Remove default_node_weight. This is not required. node_weight() only returns None if the node does not exist. If a node exists, there is always an associated node weight.<commit_after>use super::traits::{EdgeWeight, Edges, Graph};
use closed01::Closed01;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use petgraph::{EdgeDirection, Directed};
use petgraph::Graph as PetGraph;
use std::fmt::Debug;

#[derive(Debug)]
pub struct Edge {
    /// Node index type. Our graphs never exceed 4 billion nodes.
    pointing_node: u32,
    weight: EdgeWeight,
}

impl Edge {
    pub fn new_unweighted(node_idx: usize) -> Edge {
        Edge::new(node_idx, Closed01::zero())
    }

    pub fn new(node_idx: usize, weight: EdgeWeight) -> Edge {
        assert!(node_idx <= u32::max_value() as usize);
        Edge {
            pointing_node: node_idx as u32,
            weight: weight,
        }
    }
}

#[derive(Debug)]
pub struct EdgeList {
    edges: Vec<Edge>,
}

impl EdgeList {
    pub fn new(edges: Vec<Edge>) -> EdgeList {
        EdgeList { edges: edges }
    }
}

impl Edges for EdgeList {
    #[inline]
    fn num_edges(&self) -> usize {
        self.edges.len()
    }

    #[inline]
    fn nth_edge(&self, n: usize) -> Option<usize> {
        self.edges.get(n).map(|n| n.pointing_node as usize)
    }

    #[inline]
    fn nth_edge_weight(&self, n: usize) -> Option<EdgeWeight> {
        self.edges.get(n).map(|n| n.weight)
    }
}

#[derive(Debug)]
pub struct Node<T: Debug + Clone> {
    in_edges: EdgeList,
    out_edges: EdgeList,
    node_value: T,
}

impl<T: Debug + Clone> Node<T> {
    pub fn new(in_edges: EdgeList, out_edges: EdgeList, node_value: T) -> Node<T> {
        Node {
            in_edges: in_edges,
            out_edges: out_edges,
            node_value: node_value,
        }
    }

    pub fn node_value(&self) -> &T {
        &self.node_value
    }

    pub fn add_in_edge(&mut self, edge: Edge) {
        self.in_edges.edges.push(edge);
    }

    pub fn add_out_edge(&mut self, edge: Edge) {
        self.out_edges.edges.push(edge);
    }

    fn degree(&self) -> usize {
        self.in_edges.num_edges() + self.out_edges.num_edges()
    }
}

#[derive(Debug)]
pub struct OwnedGraph<T: Debug + Clone> {
    nodes: Vec<Node<T>>,
}

impl<T: Debug + Clone> OwnedGraph<T> {
    pub fn new(nodes: Vec<Node<T>>) -> OwnedGraph<T> {
        OwnedGraph { nodes: nodes }
    }

    pub fn from_petgraph(pg: &PetGraph<T, (), Directed>) -> OwnedGraph<T> {
        OwnedGraph {
            nodes: pg.node_indices()
                     .map(|i| {
                         Node::new(EdgeList::new(pg.edges_directed(i, EdgeDirection::Incoming)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   EdgeList::new(pg.edges_directed(i, EdgeDirection::Outgoing)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   pg.node_weight(i).unwrap().clone())
                     })
                     .collect(),
        }
    }

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

    pub fn push_empty_node(&mut self, node_value: T) -> usize {
        let idx = self.nodes.len();
        self.nodes.push(Node::new(EdgeList::new(Vec::new()),
                                  EdgeList::new(Vec::new()),
                                  node_value));
        return idx;
    }
}

impl<T: Debug + Clone> Graph for OwnedGraph<T> {
    type EDGE = EdgeList;
    type NODE = T;
    fn num_nodes(&self) -> usize {
        self.nodes.len()
    }

    #[inline]
    fn node_value(&self, node_idx: usize) -> &Self::NODE {
        self.nodes[node_idx].node_value()
    }

    #[inline]
    fn node_degree(&self, node_idx: usize) -> usize {
        self.nodes[node_idx].degree()
    }

    #[inline]
    fn in_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &&self.nodes[node_idx].in_edges
    }

    #[inline]
    fn out_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &self.nodes[node_idx].out_edges
    }
}

pub struct GraphBuilder<T: Debug + Clone> {
    // maps node_id to index in node_in_edges/node_out_edges.
    node_map: BTreeMap<usize, usize>,
    graph: OwnedGraph<T>,
}

impl<T: Debug + Clone> GraphBuilder<T> {
    pub fn new() -> GraphBuilder<T> {
        GraphBuilder {
            node_map: BTreeMap::new(),
            graph: OwnedGraph::new(Vec::new()),
        }
    }

    pub fn graph(self) -> OwnedGraph<T> {
        self.graph
    }

    /// Panics if `node_id` already exists.
    pub fn add_node(&mut self, node_id: usize, node_value: T) -> usize {
        match self.node_map.entry(node_id) {
            Entry::Vacant(e) => {
                let next_id = self.graph.push_empty_node(node_value);
                e.insert(next_id);
                return next_id;
            }
            Entry::Occupied(_) => {
                panic!();
            }
        }
    }

    pub fn add_edge_unweighted(&mut self, source_node_id: usize, target_node_id: usize) {
        self.add_edge(source_node_id, target_node_id, Closed01::zero());
    }

    pub fn add_edge(&mut self, source_node_id: usize, target_node_id: usize, weight: EdgeWeight) {
        let source_index = *self.node_map.get(&source_node_id).unwrap();
        let target_index = *self.node_map.get(&target_node_id).unwrap();
        self.graph.nodes[source_index].add_out_edge(Edge::new(target_index, weight));
        self.graph.nodes[target_index].add_in_edge(Edge::new(source_index, weight));
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Rectangle {
    length: u32,
    width: u32
}

impl Rectangle {
    pub fn can_hold(&self, other: &Rectangle) -> bool {
        self.length > other.length && self.width > other.width
    }
}

pub fn add_two(x: i32) -> i32 {
    x + 2
}

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

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle { length: 8, width: 8};
        let smaller = Rectangle { length:5, width: 5};

        assert!(larger.can_hold(&smaller));
    }

    #[test]
    fn smaller_can_hold_larger() {
        let larger = Rectangle { length: 8, width: 8};
        let smaller = Rectangle { length:5, width: 5};

        assert!(!smaller.can_hold(&larger));
    }

    #[test]
    fn it_adds_two() {
        assert_eq!(4, add_two(2))
    }
}
<commit_msg>Add test which uses custom error message in assert<commit_after>#[derive(Debug)]
pub struct Rectangle {
    length: u32,
    width: u32
}

impl Rectangle {
    pub fn can_hold(&self, other: &Rectangle) -> bool {
        self.length > other.length && self.width > other.width
    }
}

pub fn add_two(x: i32) -> i32 {
    x + 2
}

pub fn greeting(name: &str) -> String{
    format!("Hello, {}!", name)
}

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

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle { length: 8, width: 8};
        let smaller = Rectangle { length:5, width: 5};

        assert!(larger.can_hold(&smaller));
    }

    #[test]
    fn smaller_can_hold_larger() {
        let larger = Rectangle { length: 8, width: 8};
        let smaller = Rectangle { length:5, width: 5};

        assert!(!smaller.can_hold(&larger));
    }

    #[test]
    fn it_adds_two() {
        assert_eq!(4, add_two(2))
    }

    #[test]
    fn greeting_contains_name() {
        let result = greeting("John");
        assert!(
            result.contains("John"),
            "Greeting did not contain John, value was `{}`", result
        );
    }
}
<|endoftext|>


<commit_before>//! Shared settings module.
//!
//! This module defines data structures to access the settings defined in the meta language.
//!
//! Each settings group is translated to a `Flags` struct either in this module or in its
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
//! settings as well as computed predicate flags.
//!
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
//! create it.
//!
//! # Example
//! ```
//! use cretonne_codegen::settings::{self, Configurable};
//!
//! let mut b = settings::builder();
//! b.set("opt_level", "fastest");
//!
//! let f = settings::Flags::new(b);
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
//! ```

use constant_hash::{probe, simple_hash};
use isa::TargetIsa;
use std::boxed::Box;
use std::fmt;
use std::str;

/// A string-based configurator for settings groups.
///
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
/// struct is created.
pub trait Configurable {
    /// Set the string value of any setting by name.
    ///
    /// This can set any type of setting whether it is numeric, boolean, or enumerated.
    fn set(&mut self, name: &str, value: &str) -> SetResult<()>;

    /// Enable a boolean setting or apply a preset.
    ///
    /// If the identified setting isn't a boolean or a preset, a `BadType` error is returned.
    fn enable(&mut self, name: &str) -> SetResult<()>;
}

/// Collect settings values based on a template.
#[derive(Clone)]
pub struct Builder {
    template: &'static detail::Template,
    bytes: Box<[u8]>,
}

impl Builder {
    /// Create a new builder with defaults and names from the given template.
    pub fn new(tmpl: &'static detail::Template) -> Self {
        Self {
            template: tmpl,
            bytes: tmpl.defaults.into(),
        }
    }

    /// Extract contents of builder once everything is configured.
    pub fn state_for(&self, name: &str) -> &[u8] {
        assert_eq!(name, self.template.name);
        &self.bytes[..]
    }

    /// Set the value of a single bit.
    fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
        let byte = &mut self.bytes[offset];
        let mask = 1 << bit;
        if value {
            *byte |= mask;
        } else {
            *byte &= !mask;
        }
    }

    /// Apply a preset. The argument is a slice of (mask, value) bytes.
    fn apply_preset(&mut self, values: &[(u8, u8)]) {
        for (byte, &(mask, value)) in self.bytes.iter_mut().zip(values) {
            *byte = (*byte & !mask) | value;
        }
    }

    /// Look up a descriptor by name.
    fn lookup(&self, name: &str) -> SetResult<(usize, detail::Detail)> {
        match probe(self.template, name, simple_hash(name)) {
            Err(_) => Err(SetError::BadName),
            Ok(entry) => {
                let d = &self.template.descriptors[self.template.hash_table[entry] as usize];
                Ok((d.offset as usize, d.detail))
            }
        }
    }
}

fn parse_bool_value(value: &str) -> SetResult<bool> {
    match value {
        "true" | "on" | "yes" | "1" => Ok(true),
        "false" | "off" | "no" | "0" => Ok(false),
        _ => Err(SetError::BadValue),
    }
}

fn parse_enum_value(value: &str, choices: &[&str]) -> SetResult<u8> {
    match choices.iter().position(|&tag| tag == value) {
        Some(idx) => Ok(idx as u8),
        None => Err(SetError::BadValue),
    }
}

impl Configurable for Builder {
    fn enable(&mut self, name: &str) -> SetResult<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        match detail {
            Detail::Bool { bit } => {
                self.set_bit(offset, bit, true);
                Ok(())
            }
            Detail::Preset => {
                self.apply_preset(&self.template.presets[offset..]);
                Ok(())
            }
            _ => Err(SetError::BadType),
        }
    }

    fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        match detail {
            Detail::Bool { bit } => {
                // Cannot currently propagate SetResult<()> up on functions returning ()
                // with the `?` operator
                self.set_bit(offset, bit, parse_bool_value(value)?);
            }
            Detail::Num => {
                self.bytes[offset] = value.parse().map_err(|_| SetError::BadValue)?;
            }
            Detail::Enum { last, enumerators } => {
                self.bytes[offset] =
                    parse_enum_value(value, self.template.enums(last, enumerators))?;
            }
            Detail::Preset => return Err(SetError::BadName),
        }
        Ok(())
    }
}

/// An error produced when changing a setting.
#[derive(Debug, PartialEq, Eq)]
pub enum SetError {
    /// No setting by this name exists.
    BadName,

    /// Type mismatch for setting (e.g., setting an enum setting as a bool).
    BadType,

    /// This is not a valid value for this setting.
    BadValue,
}

/// A result returned when changing a setting.
pub type SetResult<T> = Result<T, SetError>;

/// A reference to just the boolean predicates of a settings object.
///
/// The settings objects themselves are generated and appear in the `isa/*/settings.rs` modules.
/// Each settings object provides a `predicate_view()` method that makes it possible to query
/// ISA predicates by number.
#[derive(Clone, Copy)]
pub struct PredicateView<'a>(&'a [u8]);

impl<'a> PredicateView<'a> {
    /// Create a new view of a precomputed predicate vector.
    ///
    /// See the `predicate_view()` method on the various `Flags` types defined for each ISA.
    pub fn new(bits: &'a [u8]) -> PredicateView {
        PredicateView(bits)
    }

    /// Check a numbered predicate.
    pub fn test(self, p: usize) -> bool {
        self.0[p / 8] & (1 << (p % 8)) != 0
    }
}

/// Implementation details for generated code.
///
/// This module holds definitions that need to be public so the can be instantiated by generated
/// code in other modules.
pub mod detail {
    use constant_hash;
    use std::fmt;

    /// An instruction group template.
    pub struct Template {
        /// Name of the instruction group.
        pub name: &'static str,
        /// List of setting descriptors.
        pub descriptors: &'static [Descriptor],
        /// Union of all enumerators.
        pub enumerators: &'static [&'static str],
        /// Hash table of settings.
        pub hash_table: &'static [u16],
        /// Default values.
        pub defaults: &'static [u8],
        /// Pairs of (mask, value) for presets.
        pub presets: &'static [(u8, u8)],
    }

    impl Template {
        /// Get enumerators corresponding to a `Details::Enum`.
        pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
            let from = enumerators as usize;
            let len = usize::from(last) + 1;
            &self.enumerators[from..from + len]
        }

        /// Format a setting value as a TOML string. This is mostly for use by the generated
        /// `Display` implementation.
        pub fn format_toml_value(
            &self,
            detail: Detail,
            byte: u8,
            f: &mut fmt::Formatter,
        ) -> fmt::Result {
            match detail {
                Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
                Detail::Num => write!(f, "{}", byte),
                Detail::Enum { last, enumerators } => {
                    if byte <= last {
                        let tags = self.enums(last, enumerators);
                        write!(f, "\"{}\"", tags[usize::from(byte)])
                    } else {
                        write!(f, "{}", byte)
                    }
                }
                // Presets aren't printed. They are reflected in the other settings.
                Detail::Preset { .. } => Ok(()),
            }
        }
    }

    /// The template contains a hash table for by-name lookup.
    impl<'a> constant_hash::Table<&'a str> for Template {
        fn len(&self) -> usize {
            self.hash_table.len()
        }

        fn key(&self, idx: usize) -> Option<&'a str> {
            let e = self.hash_table[idx] as usize;
            if e < self.descriptors.len() {
                Some(self.descriptors[e].name)
            } else {
                None
            }
        }
    }

    /// A setting descriptor holds the information needed to generically set and print a setting.
    ///
    /// Each settings group will be represented as a constant DESCRIPTORS array.
    pub struct Descriptor {
        /// Lower snake-case name of setting as defined in meta.
        pub name: &'static str,

        /// Offset of byte containing this setting.
        pub offset: u32,

        /// Additional details, depending on the kind of setting.
        pub detail: Detail,
    }

    /// The different kind of settings along with descriptor bits that depend on the kind.
    #[derive(Clone, Copy)]
    pub enum Detail {
        /// A boolean setting only uses one bit, numbered from LSB.
        Bool {
            /// 0-7.
            bit: u8,
        },

        /// A numerical setting uses the whole byte.
        Num,

        /// An Enum setting uses a range of enumerators.
        Enum {
            /// Numerical value of last enumerator, allowing for 1-256 enumerators.
            last: u8,

            /// First enumerator in the ENUMERATORS table.
            enumerators: u16,
        },

        /// A preset is not an individual setting, it is a collection of settings applied at once.
        ///
        /// The `Descriptor::offset` field refers to the `PRESETS` table.
        Preset,
    }

    impl Detail {
        /// Check if a detail is a Detail::Preset. Useful because the Descriptor
        /// offset field has a different meaning when the detail is a preset.
        pub fn is_preset(&self) -> bool {
            match *self {
                Detail::Preset => true,
                _ => false,
            }
        }
    }
}

// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
// with an impl for all of the settings defined in `lib/codegen/meta/base/settings.py`.
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

/// Wrapper containing flags and optionally a `TargetIsa` trait object.
///
/// A few passes need to access the flags but only optionally a target ISA. The `FlagsOrIsa`
/// wrapper can be used to pass either, and extract the flags so they are always accessible.
#[derive(Clone, Copy)]
pub struct FlagsOrIsa<'a> {
    /// Flags are always present.
    pub flags: &'a Flags,

    /// The ISA may not be present.
    pub isa: Option<&'a TargetIsa>,
}

impl<'a> From<&'a Flags> for FlagsOrIsa<'a> {
    fn from(flags: &'a Flags) -> FlagsOrIsa {
        FlagsOrIsa { flags, isa: None }
    }
}

impl<'a> From<&'a TargetIsa> for FlagsOrIsa<'a> {
    fn from(isa: &'a TargetIsa) -> FlagsOrIsa {
        FlagsOrIsa {
            flags: isa.flags(),
            isa: Some(isa),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Configurable;
    use super::SetError::*;
    use super::{builder, Flags};
    use std::string::ToString;

    #[test]
    fn display_default() {
        let b = builder();
        let f = Flags::new(b);
        assert_eq!(
            f.to_string(),
            "[shared]\n\
             opt_level = \"default\"\n\
             enable_verifier = true\n\
             call_conv = \"fast\"\n\
             is_pic = false\n\
             colocated_libcalls = false\n\
             return_at_end = false\n\
             avoid_div_traps = false\n\
             enable_float = true\n\
             enable_nan_canonicalization = false\n\
             enable_simd = true\n\
             enable_atomics = true\n\
             baldrdash_prologue_words = 0\n\
             allones_funcaddrs = false\n\
             probestack_enabled = true\n\
             probestack_func_adjusts_sp = false\n\
             probestack_size_log2 = 12\n"
        );
        assert_eq!(f.opt_level(), super::OptLevel::Default);
        assert_eq!(f.enable_simd(), true);
        assert_eq!(f.baldrdash_prologue_words(), 0);
    }

    #[test]
    fn modify_bool() {
        let mut b = builder();
        assert_eq!(b.enable("not_there"), Err(BadName));
        assert_eq!(b.enable("enable_simd"), Ok(()));
        assert_eq!(b.set("enable_simd", "false"), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
    }

    #[test]
    fn modify_string() {
        let mut b = builder();
        assert_eq!(b.set("not_there", "true"), Err(BadName));
        assert_eq!(b.set("enable_simd", ""), Err(BadValue));
        assert_eq!(b.set("enable_simd", "best"), Err(BadValue));
        assert_eq!(b.set("opt_level", "true"), Err(BadValue));
        assert_eq!(b.set("opt_level", "best"), Ok(()));
        assert_eq!(b.set("enable_simd", "0"), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
        assert_eq!(f.opt_level(), super::OptLevel::Best);
    }
}
<commit_msg>Remove an unneeded comment.<commit_after>//! Shared settings module.
//!
//! This module defines data structures to access the settings defined in the meta language.
//!
//! Each settings group is translated to a `Flags` struct either in this module or in its
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
//! settings as well as computed predicate flags.
//!
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
//! create it.
//!
//! # Example
//! ```
//! use cretonne_codegen::settings::{self, Configurable};
//!
//! let mut b = settings::builder();
//! b.set("opt_level", "fastest");
//!
//! let f = settings::Flags::new(b);
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
//! ```

use constant_hash::{probe, simple_hash};
use isa::TargetIsa;
use std::boxed::Box;
use std::fmt;
use std::str;

/// A string-based configurator for settings groups.
///
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
/// struct is created.
pub trait Configurable {
    /// Set the string value of any setting by name.
    ///
    /// This can set any type of setting whether it is numeric, boolean, or enumerated.
    fn set(&mut self, name: &str, value: &str) -> SetResult<()>;

    /// Enable a boolean setting or apply a preset.
    ///
    /// If the identified setting isn't a boolean or a preset, a `BadType` error is returned.
    fn enable(&mut self, name: &str) -> SetResult<()>;
}

/// Collect settings values based on a template.
#[derive(Clone)]
pub struct Builder {
    template: &'static detail::Template,
    bytes: Box<[u8]>,
}

impl Builder {
    /// Create a new builder with defaults and names from the given template.
    pub fn new(tmpl: &'static detail::Template) -> Self {
        Self {
            template: tmpl,
            bytes: tmpl.defaults.into(),
        }
    }

    /// Extract contents of builder once everything is configured.
    pub fn state_for(&self, name: &str) -> &[u8] {
        assert_eq!(name, self.template.name);
        &self.bytes[..]
    }

    /// Set the value of a single bit.
    fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
        let byte = &mut self.bytes[offset];
        let mask = 1 << bit;
        if value {
            *byte |= mask;
        } else {
            *byte &= !mask;
        }
    }

    /// Apply a preset. The argument is a slice of (mask, value) bytes.
    fn apply_preset(&mut self, values: &[(u8, u8)]) {
        for (byte, &(mask, value)) in self.bytes.iter_mut().zip(values) {
            *byte = (*byte & !mask) | value;
        }
    }

    /// Look up a descriptor by name.
    fn lookup(&self, name: &str) -> SetResult<(usize, detail::Detail)> {
        match probe(self.template, name, simple_hash(name)) {
            Err(_) => Err(SetError::BadName),
            Ok(entry) => {
                let d = &self.template.descriptors[self.template.hash_table[entry] as usize];
                Ok((d.offset as usize, d.detail))
            }
        }
    }
}

fn parse_bool_value(value: &str) -> SetResult<bool> {
    match value {
        "true" | "on" | "yes" | "1" => Ok(true),
        "false" | "off" | "no" | "0" => Ok(false),
        _ => Err(SetError::BadValue),
    }
}

fn parse_enum_value(value: &str, choices: &[&str]) -> SetResult<u8> {
    match choices.iter().position(|&tag| tag == value) {
        Some(idx) => Ok(idx as u8),
        None => Err(SetError::BadValue),
    }
}

impl Configurable for Builder {
    fn enable(&mut self, name: &str) -> SetResult<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        match detail {
            Detail::Bool { bit } => {
                self.set_bit(offset, bit, true);
                Ok(())
            }
            Detail::Preset => {
                self.apply_preset(&self.template.presets[offset..]);
                Ok(())
            }
            _ => Err(SetError::BadType),
        }
    }

    fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        match detail {
            Detail::Bool { bit } => {
                self.set_bit(offset, bit, parse_bool_value(value)?);
            }
            Detail::Num => {
                self.bytes[offset] = value.parse().map_err(|_| SetError::BadValue)?;
            }
            Detail::Enum { last, enumerators } => {
                self.bytes[offset] =
                    parse_enum_value(value, self.template.enums(last, enumerators))?;
            }
            Detail::Preset => return Err(SetError::BadName),
        }
        Ok(())
    }
}

/// An error produced when changing a setting.
#[derive(Debug, PartialEq, Eq)]
pub enum SetError {
    /// No setting by this name exists.
    BadName,

    /// Type mismatch for setting (e.g., setting an enum setting as a bool).
    BadType,

    /// This is not a valid value for this setting.
    BadValue,
}

/// A result returned when changing a setting.
pub type SetResult<T> = Result<T, SetError>;

/// A reference to just the boolean predicates of a settings object.
///
/// The settings objects themselves are generated and appear in the `isa/*/settings.rs` modules.
/// Each settings object provides a `predicate_view()` method that makes it possible to query
/// ISA predicates by number.
#[derive(Clone, Copy)]
pub struct PredicateView<'a>(&'a [u8]);

impl<'a> PredicateView<'a> {
    /// Create a new view of a precomputed predicate vector.
    ///
    /// See the `predicate_view()` method on the various `Flags` types defined for each ISA.
    pub fn new(bits: &'a [u8]) -> PredicateView {
        PredicateView(bits)
    }

    /// Check a numbered predicate.
    pub fn test(self, p: usize) -> bool {
        self.0[p / 8] & (1 << (p % 8)) != 0
    }
}

/// Implementation details for generated code.
///
/// This module holds definitions that need to be public so the can be instantiated by generated
/// code in other modules.
pub mod detail {
    use constant_hash;
    use std::fmt;

    /// An instruction group template.
    pub struct Template {
        /// Name of the instruction group.
        pub name: &'static str,
        /// List of setting descriptors.
        pub descriptors: &'static [Descriptor],
        /// Union of all enumerators.
        pub enumerators: &'static [&'static str],
        /// Hash table of settings.
        pub hash_table: &'static [u16],
        /// Default values.
        pub defaults: &'static [u8],
        /// Pairs of (mask, value) for presets.
        pub presets: &'static [(u8, u8)],
    }

    impl Template {
        /// Get enumerators corresponding to a `Details::Enum`.
        pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
            let from = enumerators as usize;
            let len = usize::from(last) + 1;
            &self.enumerators[from..from + len]
        }

        /// Format a setting value as a TOML string. This is mostly for use by the generated
        /// `Display` implementation.
        pub fn format_toml_value(
            &self,
            detail: Detail,
            byte: u8,
            f: &mut fmt::Formatter,
        ) -> fmt::Result {
            match detail {
                Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
                Detail::Num => write!(f, "{}", byte),
                Detail::Enum { last, enumerators } => {
                    if byte <= last {
                        let tags = self.enums(last, enumerators);
                        write!(f, "\"{}\"", tags[usize::from(byte)])
                    } else {
                        write!(f, "{}", byte)
                    }
                }
                // Presets aren't printed. They are reflected in the other settings.
                Detail::Preset { .. } => Ok(()),
            }
        }
    }

    /// The template contains a hash table for by-name lookup.
    impl<'a> constant_hash::Table<&'a str> for Template {
        fn len(&self) -> usize {
            self.hash_table.len()
        }

        fn key(&self, idx: usize) -> Option<&'a str> {
            let e = self.hash_table[idx] as usize;
            if e < self.descriptors.len() {
                Some(self.descriptors[e].name)
            } else {
                None
            }
        }
    }

    /// A setting descriptor holds the information needed to generically set and print a setting.
    ///
    /// Each settings group will be represented as a constant DESCRIPTORS array.
    pub struct Descriptor {
        /// Lower snake-case name of setting as defined in meta.
        pub name: &'static str,

        /// Offset of byte containing this setting.
        pub offset: u32,

        /// Additional details, depending on the kind of setting.
        pub detail: Detail,
    }

    /// The different kind of settings along with descriptor bits that depend on the kind.
    #[derive(Clone, Copy)]
    pub enum Detail {
        /// A boolean setting only uses one bit, numbered from LSB.
        Bool {
            /// 0-7.
            bit: u8,
        },

        /// A numerical setting uses the whole byte.
        Num,

        /// An Enum setting uses a range of enumerators.
        Enum {
            /// Numerical value of last enumerator, allowing for 1-256 enumerators.
            last: u8,

            /// First enumerator in the ENUMERATORS table.
            enumerators: u16,
        },

        /// A preset is not an individual setting, it is a collection of settings applied at once.
        ///
        /// The `Descriptor::offset` field refers to the `PRESETS` table.
        Preset,
    }

    impl Detail {
        /// Check if a detail is a Detail::Preset. Useful because the Descriptor
        /// offset field has a different meaning when the detail is a preset.
        pub fn is_preset(&self) -> bool {
            match *self {
                Detail::Preset => true,
                _ => false,
            }
        }
    }
}

// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
// with an impl for all of the settings defined in `lib/codegen/meta/base/settings.py`.
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

/// Wrapper containing flags and optionally a `TargetIsa` trait object.
///
/// A few passes need to access the flags but only optionally a target ISA. The `FlagsOrIsa`
/// wrapper can be used to pass either, and extract the flags so they are always accessible.
#[derive(Clone, Copy)]
pub struct FlagsOrIsa<'a> {
    /// Flags are always present.
    pub flags: &'a Flags,

    /// The ISA may not be present.
    pub isa: Option<&'a TargetIsa>,
}

impl<'a> From<&'a Flags> for FlagsOrIsa<'a> {
    fn from(flags: &'a Flags) -> FlagsOrIsa {
        FlagsOrIsa { flags, isa: None }
    }
}

impl<'a> From<&'a TargetIsa> for FlagsOrIsa<'a> {
    fn from(isa: &'a TargetIsa) -> FlagsOrIsa {
        FlagsOrIsa {
            flags: isa.flags(),
            isa: Some(isa),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Configurable;
    use super::SetError::*;
    use super::{builder, Flags};
    use std::string::ToString;

    #[test]
    fn display_default() {
        let b = builder();
        let f = Flags::new(b);
        assert_eq!(
            f.to_string(),
            "[shared]\n\
             opt_level = \"default\"\n\
             enable_verifier = true\n\
             call_conv = \"fast\"\n\
             is_pic = false\n\
             colocated_libcalls = false\n\
             return_at_end = false\n\
             avoid_div_traps = false\n\
             enable_float = true\n\
             enable_nan_canonicalization = false\n\
             enable_simd = true\n\
             enable_atomics = true\n\
             baldrdash_prologue_words = 0\n\
             allones_funcaddrs = false\n\
             probestack_enabled = true\n\
             probestack_func_adjusts_sp = false\n\
             probestack_size_log2 = 12\n"
        );
        assert_eq!(f.opt_level(), super::OptLevel::Default);
        assert_eq!(f.enable_simd(), true);
        assert_eq!(f.baldrdash_prologue_words(), 0);
    }

    #[test]
    fn modify_bool() {
        let mut b = builder();
        assert_eq!(b.enable("not_there"), Err(BadName));
        assert_eq!(b.enable("enable_simd"), Ok(()));
        assert_eq!(b.set("enable_simd", "false"), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
    }

    #[test]
    fn modify_string() {
        let mut b = builder();
        assert_eq!(b.set("not_there", "true"), Err(BadName));
        assert_eq!(b.set("enable_simd", ""), Err(BadValue));
        assert_eq!(b.set("enable_simd", "best"), Err(BadValue));
        assert_eq!(b.set("opt_level", "true"), Err(BadValue));
        assert_eq!(b.set("opt_level", "best"), Ok(()));
        assert_eq!(b.set("enable_simd", "0"), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
        assert_eq!(f.opt_level(), super::OptLevel::Best);
    }
}
<|endoftext|>


<commit_before>use crate::identifier::Identifier;
use crate::{BuildMetadata, Comparator, Prerelease, VersionReq};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::iter::FromIterator;
use core::ops::Deref;

impl Default for Identifier {
    fn default() -> Self {
        Identifier::empty()
    }
}

impl Eq for Identifier {}

impl Hash for Identifier {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.as_str().hash(hasher);
    }
}

impl Deref for Prerelease {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.identifier.as_str()
    }
}

impl Deref for BuildMetadata {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.identifier.as_str()
    }
}

impl PartialOrd for Prerelease {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(Ord::cmp(self, rhs))
    }
}

impl PartialOrd for BuildMetadata {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(Ord::cmp(self, rhs))
    }
}

impl Ord for Prerelease {
    fn cmp(&self, rhs: &Self) -> Ordering {
        match self.is_empty() {
            true if rhs.is_empty() => return Ordering::Equal,
            // A real release compares greater than prerelease.
            true => return Ordering::Greater,
            // Prerelease compares less than the real release.
            false if rhs.is_empty() => return Ordering::Less,
            false => {}
        }

        let lhs = self.as_str().split('.');
        let mut rhs = rhs.as_str().split('.');

        for lhs in lhs {
            let rhs = match rhs.next() {
                // Spec: "A larger set of pre-release fields has a higher
                // precedence than a smaller set, if all of the preceding
                // identifiers are equal."
                None => return Ordering::Greater,
                Some(rhs) => rhs,
            };

            let string_cmp = || Ord::cmp(lhs, rhs);
            let is_ascii_digit = |b: u8| b.is_ascii_digit();
            let ordering = match (
                lhs.bytes().all(is_ascii_digit),
                rhs.bytes().all(is_ascii_digit),
            ) {
                // Respect numeric ordering, for example 99 < 100. Spec says:
                // "Identifiers consisting of only digits are compared
                // numerically."
                (true, true) => Ord::cmp(&lhs.len(), &rhs.len()).then_with(string_cmp),
                // Spec: "Numeric identifiers always have lower precedence than
                // non-numeric identifiers."
                (true, false) => return Ordering::Less,
                (false, true) => return Ordering::Greater,
                // Spec: "Identifiers with letters or hyphens are compared
                // lexically in ASCII sort order."
                (false, false) => string_cmp(),
            };

            if ordering != Ordering::Equal {
                return ordering;
            }
        }

        if rhs.next().is_none() {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

impl Ord for BuildMetadata {
    fn cmp(&self, rhs: &Self) -> Ordering {
        let lhs = self.as_str().split('.');
        let mut rhs = rhs.as_str().split('.');

        for lhs in lhs {
            let rhs = match rhs.next() {
                None => return Ordering::Greater,
                Some(rhs) => rhs,
            };

            let is_ascii_digit = |b: u8| b.is_ascii_digit();
            let ordering = match (
                lhs.bytes().all(is_ascii_digit),
                rhs.bytes().all(is_ascii_digit),
            ) {
                (true, true) => {
                    // 0 < 00 < 1 < 01 < 001 < 2 < 02 < 002 < 10
                    let lhval = lhs.trim_start_matches('0');
                    let rhval = rhs.trim_start_matches('0');
                    Ord::cmp(&lhval.len(), &rhval.len())
                        .then_with(|| Ord::cmp(lhval, rhval))
                        .then_with(|| Ord::cmp(&lhs.len(), &rhs.len()))
                }
                (true, false) => return Ordering::Less,
                (false, true) => return Ordering::Greater,
                (false, false) => Ord::cmp(lhs, rhs),
            };

            if ordering != Ordering::Equal {
                return ordering;
            }
        }

        if rhs.next().is_none() {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

impl FromIterator<Comparator> for VersionReq {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = Comparator>,
    {
        let comparators = Vec::from_iter(iter);
        VersionReq { comparators }
    }
}
<commit_msg>Fix FromIterator impl on no-std<commit_after>use crate::backport::*;
use crate::identifier::Identifier;
use crate::{BuildMetadata, Comparator, Prerelease, VersionReq};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::iter::FromIterator;
use core::ops::Deref;

impl Default for Identifier {
    fn default() -> Self {
        Identifier::empty()
    }
}

impl Eq for Identifier {}

impl Hash for Identifier {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.as_str().hash(hasher);
    }
}

impl Deref for Prerelease {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.identifier.as_str()
    }
}

impl Deref for BuildMetadata {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.identifier.as_str()
    }
}

impl PartialOrd for Prerelease {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(Ord::cmp(self, rhs))
    }
}

impl PartialOrd for BuildMetadata {
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
        Some(Ord::cmp(self, rhs))
    }
}

impl Ord for Prerelease {
    fn cmp(&self, rhs: &Self) -> Ordering {
        match self.is_empty() {
            true if rhs.is_empty() => return Ordering::Equal,
            // A real release compares greater than prerelease.
            true => return Ordering::Greater,
            // Prerelease compares less than the real release.
            false if rhs.is_empty() => return Ordering::Less,
            false => {}
        }

        let lhs = self.as_str().split('.');
        let mut rhs = rhs.as_str().split('.');

        for lhs in lhs {
            let rhs = match rhs.next() {
                // Spec: "A larger set of pre-release fields has a higher
                // precedence than a smaller set, if all of the preceding
                // identifiers are equal."
                None => return Ordering::Greater,
                Some(rhs) => rhs,
            };

            let string_cmp = || Ord::cmp(lhs, rhs);
            let is_ascii_digit = |b: u8| b.is_ascii_digit();
            let ordering = match (
                lhs.bytes().all(is_ascii_digit),
                rhs.bytes().all(is_ascii_digit),
            ) {
                // Respect numeric ordering, for example 99 < 100. Spec says:
                // "Identifiers consisting of only digits are compared
                // numerically."
                (true, true) => Ord::cmp(&lhs.len(), &rhs.len()).then_with(string_cmp),
                // Spec: "Numeric identifiers always have lower precedence than
                // non-numeric identifiers."
                (true, false) => return Ordering::Less,
                (false, true) => return Ordering::Greater,
                // Spec: "Identifiers with letters or hyphens are compared
                // lexically in ASCII sort order."
                (false, false) => string_cmp(),
            };

            if ordering != Ordering::Equal {
                return ordering;
            }
        }

        if rhs.next().is_none() {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

impl Ord for BuildMetadata {
    fn cmp(&self, rhs: &Self) -> Ordering {
        let lhs = self.as_str().split('.');
        let mut rhs = rhs.as_str().split('.');

        for lhs in lhs {
            let rhs = match rhs.next() {
                None => return Ordering::Greater,
                Some(rhs) => rhs,
            };

            let is_ascii_digit = |b: u8| b.is_ascii_digit();
            let ordering = match (
                lhs.bytes().all(is_ascii_digit),
                rhs.bytes().all(is_ascii_digit),
            ) {
                (true, true) => {
                    // 0 < 00 < 1 < 01 < 001 < 2 < 02 < 002 < 10
                    let lhval = lhs.trim_start_matches('0');
                    let rhval = rhs.trim_start_matches('0');
                    Ord::cmp(&lhval.len(), &rhval.len())
                        .then_with(|| Ord::cmp(lhval, rhval))
                        .then_with(|| Ord::cmp(&lhs.len(), &rhs.len()))
                }
                (true, false) => return Ordering::Less,
                (false, true) => return Ordering::Greater,
                (false, false) => Ord::cmp(lhs, rhs),
            };

            if ordering != Ordering::Equal {
                return ordering;
            }
        }

        if rhs.next().is_none() {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

impl FromIterator<Comparator> for VersionReq {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = Comparator>,
    {
        let comparators = Vec::from_iter(iter);
        VersionReq { comparators }
    }
}
<|endoftext|>