<commit_before>//
// base32.rs - base32 implementation
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//
// The "Extended Hex" Base 32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 0             9 9            18 I            27 R
//     1 1            10 A            19 J            28 S
//     2 2            11 B            20 K            29 T
//     3 3            12 C            21 L            30 U
//     4 4            13 D            22 M            31 V
//     5 5            14 E            23 N
//     6 6            15 F            24 O         (pad) =
//     7 7            16 G            25 P
//     8 8            17 H            26 Q
//

use std;

export base32, mk;

const padd: u8 = 61u8;

iface base32 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn hex_encode(src: [u8]) -> [u8];
    fn hex_decode(src: [u8]) -> [u8];
}

fn mk() -> base32 {
    type _base32 = {table: [u8], table_hex: [u8]};

    impl of base32 for _base32 {
        fn encode(src: [u8]) -> [u8] {
            b32encode(self.table, src)
        }
        fn decode(src: [u8]) -> [u8] {
            b32decode(self.table, src)
        }
        fn hex_encode(src: [u8]) -> [u8] {
            b32encode(self.table_hex, src)
        }
        fn hex_decode(src: [u8]) -> [u8] {
            b32decode(self.table_hex, src)
        }
    }

    let table = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(50u8, 56u8)  { |j| table[i] = j; i += 1u8; }

    let table_hex = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(48u8, 58u8)  { |j| table_hex[i] = j; i += 1u8; }
    u8::range(65u8, 87u8)  { |j| table_hex[i] = j; i += 1u8; }

    {table: vec::from_mut(table),
     table_hex: vec::from_mut(table_hex)} as base32
}

fn b32encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ = if srclen % 5u == 0u {
        vec::init_elt_mut(srclen / 5u * 8u, 0u8)
    } else {
        vec::init_elt_mut((srclen / 5u + 1u) * 8u, 0u8)
    };
    let input = vec::init_elt_mut(5u, 0u8);
    let output = vec::init_elt_mut(8u, 0u8);
    let curr = 0u, src_curr = 0u;

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        srclen -= 5u; src_curr += 5u;

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;
        output[7] = input[4] & 0x1f_u8;

        targ[curr + 0u] = table[output[0]];
        targ[curr + 1u] = table[output[1]];
        targ[curr + 2u] = table[output[2]];
        targ[curr + 3u] = table[output[3]];
        targ[curr + 4u] = table[output[4]];
        targ[curr + 5u] = table[output[5]];
        targ[curr + 6u] = table[output[6]];
        targ[curr + 7u] = table[output[7]];
        curr += 8u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;
        input[3] = 0u8; input[4] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          3u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];}
          4u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];
              input[3] = src[src_curr + 3u];}
          _ { }
        }

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;

        targ[curr + 0u] = table[output[0]];
        targ[curr + 1u] = table[output[1]];
        targ[curr + 2u] = if srclen > 1u { table[output[2]] } else { padd };
        targ[curr + 3u] = if srclen > 1u { table[output[3]] } else { padd };
        targ[curr + 4u] = if srclen > 2u { table[output[4]] } else { padd };
        targ[curr + 5u] = if srclen > 3u { table[output[5]] } else { padd };
        targ[curr + 6u] = if srclen > 3u { table[output[6]] } else { padd };
        targ[curr + 7u] = padd;
    }

    vec::from_mut(targ)
}

fn b32decode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 8u != 0u { fail "malformed base32 string"; }
    if srclen == 0u { ret []; }

    []
}

mod tests {
    import std::map;
    import core::str::{bytes, from_bytes};
    enum mode {
        t_encode,
        t_decode,
        t_hex_encode,
        t_hex_decode,
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode { }
          t_encode {
            m.insert("fooba", "MZXW6YTB");
            m.insert("foob",  "MZXW6YQ=");
            m.insert("foo",   "MZXW6===");
            m.insert("fo",    "MZXQ====");
            m.insert("f",     "MY======");
          }
          t_hex_decode { }
          t_hex_encode {
            m.insert("fooba", "CPNMUOJ1");
            m.insert("foob",  "CPNMUOG=");
            m.insert("foo",   "CPNMU===");
            m.insert("fo",    "CPNG====");
            m.insert("f",     "CO======");
          }
        }
        m.insert("", "");
        m
    }
    fn do_test(t: mode) {
        let b32 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b32.decode(bytes(k))) }
              t_encode { from_bytes(b32.encode(bytes(k))) }
              t_hex_decode { from_bytes(b32.hex_decode(bytes(k))) }
              t_hex_encode { from_bytes(b32.hex_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn hex_encode() { do_test(t_hex_encode); }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn hex_decode() { do_test(t_hex_decode); }
}
<commit_msg>wip: base32.rs<commit_after>//
// base32.rs - base32 implementation
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//
// The "Extended Hex" Base 32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 0             9 9            18 I            27 R
//     1 1            10 A            19 J            28 S
//     2 2            11 B            20 K            29 T
//     3 3            12 C            21 L            30 U
//     4 4            13 D            22 M            31 V
//     5 5            14 E            23 N
//     6 6            15 F            24 O         (pad) =
//     7 7            16 G            25 P
//     8 8            17 H            26 Q
//

use std;

export base32, mk;

const padd: u8 = 61u8;

iface base32 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn hex_encode(src: [u8]) -> [u8];
    fn hex_decode(src: [u8]) -> [u8];
}

fn mk() -> base32 {
    type _base32 = {table: [u8], table_hex: [u8]};

    impl of base32 for _base32 {
        fn encode(src: [u8]) -> [u8] {
            b32encode(self.table, src)
        }
        fn decode(src: [u8]) -> [u8] {
            b32decode(self.table, src)
        }
        fn hex_encode(src: [u8]) -> [u8] {
            b32encode(self.table_hex, src)
        }
        fn hex_decode(src: [u8]) -> [u8] {
            b32decode(self.table_hex, src)
        }
    }

    let table = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(50u8, 56u8)  { |j| table[i] = j; i += 1u8; }

    let table_hex = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(48u8, 58u8)  { |j| table_hex[i] = j; i += 1u8; }
    u8::range(65u8, 87u8)  { |j| table_hex[i] = j; i += 1u8; }

    {table: vec::from_mut(table),
     table_hex: vec::from_mut(table_hex)} as base32
}

fn b32encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ = if srclen % 5u == 0u {
        vec::init_elt_mut(srclen / 5u * 8u, 0u8)
    } else {
        vec::init_elt_mut((srclen / 5u + 1u) * 8u, 0u8)
    };
    let input = vec::init_elt_mut(5u, 0u8);
    let output = vec::init_elt_mut(8u, 0u8);
    let curr = 0u, src_curr = 0u;

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        srclen -= 5u; src_curr += 5u;

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;
        output[7] = input[4] & 0x1f_u8;

        targ[curr + 0u] = table[output[0]];
        targ[curr + 1u] = table[output[1]];
        targ[curr + 2u] = table[output[2]];
        targ[curr + 3u] = table[output[3]];
        targ[curr + 4u] = table[output[4]];
        targ[curr + 5u] = table[output[5]];
        targ[curr + 6u] = table[output[6]];
        targ[curr + 7u] = table[output[7]];
        curr += 8u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;
        input[3] = 0u8; input[4] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          3u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];}
          4u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];
              input[3] = src[src_curr + 3u];}
          _ { }
        }

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;

        targ[curr + 0u] = table[output[0]];
        targ[curr + 1u] = table[output[1]];
        targ[curr + 2u] = if srclen > 1u { table[output[2]] } else { padd };
        targ[curr + 3u] = if srclen > 1u { table[output[3]] } else { padd };
        targ[curr + 4u] = if srclen > 2u { table[output[4]] } else { padd };
        targ[curr + 5u] = if srclen > 3u { table[output[5]] } else { padd };
        targ[curr + 6u] = if srclen > 3u { table[output[6]] } else { padd };
        targ[curr + 7u] = padd;
    }

    vec::from_mut(targ)
}

fn b32decode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 8u != 0u { fail "malformed base32 string"; }
    if srclen == 0u { ret []; }

    let input = vec::init_elt_mut(8u, 0u8);
    let output = vec::init_elt_mut(8u, 0u8);
    let targ = if src[srclen - 6u] == padd {
        vec::init_elt_mut(srclen / 8u * 5u - 4u, 0u8)
    } else if src[srclen - 4u] == padd {
        vec::init_elt_mut(srclen / 8u * 5u - 3u, 0u8)
    } else if src[srclen - 3u] == padd {
        vec::init_elt_mut(srclen / 8u * 5u - 2u, 0u8)
    } else if src[srclen - 1u] == padd {
        vec::init_elt_mut(srclen / 8u * 5u - 1u, 0u8)
    } else {
        vec::init_elt_mut(srclen / 8u * 5u, 0u8)
    };
    let curr = 0u, src_curr = 0u;

    vec::from_mut(targ)
}

mod tests {
    import std::map;
    import core::str::{bytes, from_bytes};
    enum mode {
        t_encode,
        t_decode,
        t_hex_encode,
        t_hex_decode,
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode { }
          t_encode {
            m.insert("fooba", "MZXW6YTB");
            m.insert("foob",  "MZXW6YQ=");
            m.insert("foo",   "MZXW6===");
            m.insert("fo",    "MZXQ====");
            m.insert("f",     "MY======");
          }
          t_hex_decode { }
          t_hex_encode {
            m.insert("fooba", "CPNMUOJ1");
            m.insert("foob",  "CPNMUOG=");
            m.insert("foo",   "CPNMU===");
            m.insert("fo",    "CPNG====");
            m.insert("f",     "CO======");
          }
        }
        m.insert("", "");
        m
    }
    fn do_test(t: mode) {
        let b32 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b32.decode(bytes(k))) }
              t_encode { from_bytes(b32.encode(bytes(k))) }
              t_hex_decode { from_bytes(b32.hex_decode(bytes(k))) }
              t_hex_encode { from_bytes(b32.hex_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn hex_encode() { do_test(t_hex_encode); }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn hex_decode() { do_test(t_hex_decode); }
}
<|endoftext|>


<commit_before>//! Implements `MoveStack`.

use moves::{Move, MoveDigest, AddMove};

/// Stores a list of moves for each position in a given line of play.
///
/// # Examples:
///
/// ```rust
/// # use alcibiades::Move;
/// # use alcibiades::utils::MoveStack;
/// let mut s = MoveStack::new();
/// assert_eq!(s.ply(), 0);
/// assert_eq!(s.list().len(), 0);
/// s.push(Move::invalid());
/// s.push(Move::invalid());
/// assert_eq!(s.list().len(), 2);
/// let first_move = s.pull_best();
/// assert_eq!(s.list().len(), 1);
/// s.save();
/// assert_eq!(s.ply(), 1);
/// assert_eq!(s.list().len(), 0);
/// s.restore();
/// assert_eq!(s.ply(), 0);
/// assert_eq!(s.list().len(), 1);
/// let second_move = s.pull_best();
/// assert_eq!(s.list().len(), 0);
/// ```
pub struct MoveStack {
    moves: Vec<Move>,
    savepoints: Vec<usize>,
    first_move_index: usize,
}

impl AddMove for MoveStack {
    /// Appends a move to the end of the current move list.
    #[inline(always)]
    fn add_move(&mut self, m: Move) {
        self.push(m);
    }
}

impl MoveStack {
    /// Creates a new (empty) instance.
    pub fn new() -> MoveStack {
        MoveStack {
            moves: Vec::with_capacity(32 * 64),
            savepoints: Vec::with_capacity(32),
            first_move_index: 0,
        }
    }

    /// Saves the current move list and replaces it with an empty one.
    ///
    /// This method can be called many times. At each call the current
    /// move list will be saved to the stack of lists that can later
    /// be restored. After calling `save` the new current move list
    /// will be empty.
    #[inline]
    pub fn save(&mut self) {
        self.savepoints.push(self.first_move_index);
        self.first_move_index = self.moves.len();
    }

    /// Restores the last saved move list.
    ///
    /// The current move list is lost.
    ///
    /// # Panics
    ///
    /// Panics if there are no saved move lists left.
    #[inline]
    pub fn restore(&mut self) {
        self.moves.truncate(self.first_move_index);
        self.first_move_index = self.savepoints.pop().unwrap();
    }

    /// Returns the number of saved move lists.
    ///
    /// The number of saved move lists starts at zero. It is
    /// incremented on each call to `save`, and decremented on each
    /// call to `restore`.
    #[inline]
    pub fn ply(&self) -> usize {
        self.savepoints.len()
    }

    /// Clears the current move list, removing all moves from it.
    #[inline]
    pub fn clear(&mut self) {
        self.moves.truncate(self.first_move_index);
    }

    /// Clears the current move list and deletes all saved move lists.
    #[inline]
    pub fn clear_all(&mut self) {
        self.moves.clear();
        self.savepoints.clear();
        self.first_move_index = 0;
    }

    /// Appends a move to the end of the current move list.
    #[inline]
    pub fn push(&mut self, m: Move) {
        debug_assert!(self.moves.len() >= self.first_move_index);
        self.moves.push(m);
    }

    /// Removes the last move from the current move list and returns it.
    ///
    /// If the current move list is empty, `None` is returned.
    #[inline]
    pub fn pop(&mut self) -> Option<Move> {
        debug_assert!(self.moves.len() >= self.first_move_index);
        if self.moves.len() > self.first_move_index {
            self.moves.pop()
        } else {
            None
        }
    }

    /// Removes the move at given index from the current move list and
    /// returns it.
    ///
    /// Move's slot is taken by the last move in the current list, and
    /// the last slot is discarded.
    ///
    /// # Panics
    ///
    /// Panics if there is no move at the given index.
    #[inline]
    pub fn pull(&mut self, index: usize) -> Move {
        let last_move = *self.moves.last().unwrap();
        let m;
        {
            let requested_slot = &mut self.moves[self.first_move_index + index];
            m = *requested_slot;
            *requested_slot = last_move;
        }
        self.moves.pop();
        m
    }

    /// Removes a specific move from the current move list and returns it.
    ///
    /// This method tries to find a move `m` for which `m.digest() ==
    /// move_digest`. If such move is found, `Some(m)` is returned,
    /// move's slot is taken by the last move in the current list, and
    /// the last slot is discarded. If no such move is found, `None`
    /// is returned.
    #[inline]
    pub fn pull_move(&mut self, move_digest: MoveDigest) -> Option<Move> {
        debug_assert!(self.moves.len() >= self.first_move_index);

        // The last move in `self.moves` will take the place of the
        // removed move.
        let last_move = if let Some(last) = self.moves.last() {
            *last
        } else {
            return None;
        };

        let m;
        'moves: loop {
            for curr in self.list_mut().iter_mut() {
                if curr.digest() == move_digest {
                    m = *curr;
                    *curr = last_move;
                    break 'moves;
                }
            }
            return None;
        }
        debug_assert!(!self.moves.is_empty());
        self.moves.pop();
        Some(m)
    }

    /// Removes the move with the highest value from the current move
    /// list and returns it.
    ///
    /// Best move's slot is taken by the last move in the current
    /// list, and the last slot is discarded. `None` is returned if
    /// the current move list is empty.
    #[inline]
    pub fn pull_best(&mut self) -> Option<Move> {
        debug_assert!(self.moves.len() >= self.first_move_index);
        let moves = &mut self.moves;
        if moves.len() > self.first_move_index {
            let last = moves.len() - 1;
            unsafe {
                let mut best_move = *moves.get_unchecked(last);
                let mut curr = last;
                loop {
                    if *moves.get_unchecked(curr) > best_move {
                        // Swap the new best move candidate (`curr`)
                        // with the previous candidate (`last`).
                        *moves.get_unchecked_mut(last) = *moves.get_unchecked_mut(curr);
                        *moves.get_unchecked_mut(curr) = best_move;
                        best_move = *moves.get_unchecked(last);
                    }
                    if curr == self.first_move_index {
                        break;
                    }
                    curr -= 1;
                }
                moves.pop();
                return Some(best_move);
            }
        }
        None
    }

    /// Returns the current move list as a slice.
    #[inline]
    pub fn list(&self) -> &[Move] {
        debug_assert!(self.moves.len() >= self.first_move_index);
        &self.moves[self.first_move_index..]
    }

    /// Returns the current move list as a mutable slice.
    #[inline]
    pub fn list_mut(&mut self) -> &mut [Move] {
        debug_assert!(self.moves.len() >= self.first_move_index);
        &mut self.moves[self.first_move_index..]
    }
}

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

    #[should_panic]
    #[test]
    fn move_stack_pull_panic() {
        let mut s = MoveStack::new();
        s.pull(0);
    }

    #[test]
    fn move_stack() {
        let cr = CastlingRights::new(0);
        let m = Move::new(MOVE_NORMAL, E2, E4, 0, PIECE_NONE, PAWN, cr, 8, 0);
        let mut s = MoveStack::new();
        assert_eq!(s.ply(), 0);
        assert!(s.pull_best().is_none());
        s.save();
        assert_eq!(s.ply(), 1);
        s.push(m);
        assert_eq!(s.pull(0), m);
        assert!(s.pull_best().is_none());
        s.restore();
        assert!(s.pull_best().is_none());
        assert_eq!(s.list().len(), 0);
        assert!(s.pop().is_none());
        assert!(s.pull_move(m.digest()).is_none());
        s.push(m);
        s.push(m);
        assert_eq!(s.list().len(), 2);
        assert_eq!(s.pop().unwrap(), m);
        assert_eq!(s.list().len(), 1);
        s.push(m);
        assert_eq!(s.pull_move(m.digest()).unwrap(), m);
        assert_eq!(s.list().len(), 1);
        s.push(m);
        assert_eq!(s.list().iter().count(), 2);
        s.save();
        s.push(m);
        s.restore();
        assert_eq!(s.pull_best().unwrap(), m);
        assert_eq!(s.pull_best().unwrap(), m);
        assert!(s.pull_best().is_none());
        assert_eq!(s.ply(), 0);
        s.push(m);
        s.clear();
        assert_eq!(s.ply(), 0);
        assert_eq!(s.list().len(), 0);
        s.save();
        s.save();
        s.push(m);
        assert_eq!(s.ply(), 2);
        s.clear_all();
        assert_eq!(s.ply(), 0);
        assert_eq!(s.list().len(), 0);
    }
}
<commit_msg>improve MoveStack::pull_best()<commit_after>//! Implements `MoveStack`.

use moves::{Move, MoveDigest, AddMove};

/// Stores a list of moves for each position in a given line of play.
///
/// # Examples:
///
/// ```rust
/// # use alcibiades::Move;
/// # use alcibiades::utils::MoveStack;
/// let mut s = MoveStack::new();
/// assert_eq!(s.ply(), 0);
/// assert_eq!(s.list().len(), 0);
/// s.push(Move::invalid());
/// s.push(Move::invalid());
/// assert_eq!(s.list().len(), 2);
/// let first_move = s.pull_best();
/// assert_eq!(s.list().len(), 1);
/// s.save();
/// assert_eq!(s.ply(), 1);
/// assert_eq!(s.list().len(), 0);
/// s.restore();
/// assert_eq!(s.ply(), 0);
/// assert_eq!(s.list().len(), 1);
/// let second_move = s.pull_best();
/// assert_eq!(s.list().len(), 0);
/// ```
pub struct MoveStack {
    moves: Vec<Move>,
    savepoints: Vec<usize>,
    first_move_index: usize,
}

impl AddMove for MoveStack {
    /// Appends a move to the end of the current move list.
    #[inline(always)]
    fn add_move(&mut self, m: Move) {
        self.push(m);
    }
}

impl MoveStack {
    /// Creates a new (empty) instance.
    pub fn new() -> MoveStack {
        MoveStack {
            moves: Vec::with_capacity(32 * 64),
            savepoints: Vec::with_capacity(32),
            first_move_index: 0,
        }
    }

    /// Saves the current move list and replaces it with an empty one.
    ///
    /// This method can be called many times. At each call the current
    /// move list will be saved to the stack of lists that can later
    /// be restored. After calling `save` the new current move list
    /// will be empty.
    #[inline]
    pub fn save(&mut self) {
        self.savepoints.push(self.first_move_index);
        self.first_move_index = self.moves.len();
    }

    /// Restores the last saved move list.
    ///
    /// The current move list is lost.
    ///
    /// # Panics
    ///
    /// Panics if there are no saved move lists left.
    #[inline]
    pub fn restore(&mut self) {
        self.moves.truncate(self.first_move_index);
        self.first_move_index = self.savepoints.pop().unwrap();
    }

    /// Returns the number of saved move lists.
    ///
    /// The number of saved move lists starts at zero. It is
    /// incremented on each call to `save`, and decremented on each
    /// call to `restore`.
    #[inline]
    pub fn ply(&self) -> usize {
        self.savepoints.len()
    }

    /// Clears the current move list, removing all moves from it.
    #[inline]
    pub fn clear(&mut self) {
        self.moves.truncate(self.first_move_index);
    }

    /// Clears the current move list and deletes all saved move lists.
    #[inline]
    pub fn clear_all(&mut self) {
        self.moves.clear();
        self.savepoints.clear();
        self.first_move_index = 0;
    }

    /// Appends a move to the end of the current move list.
    #[inline]
    pub fn push(&mut self, m: Move) {
        debug_assert!(self.moves.len() >= self.first_move_index);
        self.moves.push(m);
    }

    /// Removes the last move from the current move list and returns it.
    ///
    /// If the current move list is empty, `None` is returned.
    #[inline]
    pub fn pop(&mut self) -> Option<Move> {
        debug_assert!(self.moves.len() >= self.first_move_index);
        if self.moves.len() > self.first_move_index {
            self.moves.pop()
        } else {
            None
        }
    }

    /// Removes the move at given index from the current move list and
    /// returns it.
    ///
    /// Move's slot is taken by the last move in the current list, and
    /// the last slot is discarded.
    ///
    /// # Panics
    ///
    /// Panics if there is no move at the given index.
    #[inline]
    pub fn pull(&mut self, index: usize) -> Move {
        let last_move = *self.moves.last().unwrap();
        let m;
        {
            let requested_slot = &mut self.moves[self.first_move_index + index];
            m = *requested_slot;
            *requested_slot = last_move;
        }
        self.moves.pop();
        m
    }

    /// Removes a specific move from the current move list and returns it.
    ///
    /// This method tries to find a move `m` for which `m.digest() ==
    /// move_digest`. If such move is found, `Some(m)` is returned,
    /// move's slot is taken by the last move in the current list, and
    /// the last slot is discarded. If no such move is found, `None`
    /// is returned.
    #[inline]
    pub fn pull_move(&mut self, move_digest: MoveDigest) -> Option<Move> {
        debug_assert!(self.moves.len() >= self.first_move_index);

        // The last move in `self.moves` will take the place of the
        // removed move.
        let last_move = if let Some(last) = self.moves.last() {
            *last
        } else {
            return None;
        };

        let m;
        'moves: loop {
            for curr in self.list_mut().iter_mut() {
                if curr.digest() == move_digest {
                    m = *curr;
                    *curr = last_move;
                    break 'moves;
                }
            }
            return None;
        }
        debug_assert!(!self.moves.is_empty());
        self.moves.pop();
        Some(m)
    }

    /// Removes the move with the highest value from the current move
    /// list and returns it.
    ///
    /// Best move's slot is taken by the last move in the current
    /// list, and the last slot is discarded. `None` is returned if
    /// the current move list is empty.
    #[inline]
    pub fn pull_best(&mut self) -> Option<Move> {
        debug_assert!(self.moves.len() >= self.first_move_index);
        let moves = &mut self.moves;
        let n = moves.len();
        if n > self.first_move_index {
            let last = n - 1;
            unsafe {
                let mut best_move = *moves.get_unchecked(last);
                let mut best = last;
                let mut i = last;
                while i > self.first_move_index {
                    i -= 1;
                    let m = *moves.get_unchecked(i);
                    if m > best_move {
                        best_move = m;
                        best = i;
                    }
                }
                *moves.get_unchecked_mut(best) = *moves.get_unchecked(last);
                moves.pop();
                return Some(best_move);
            }
        }
        None
    }

    /// Returns the current move list as a slice.
    #[inline]
    pub fn list(&self) -> &[Move] {
        debug_assert!(self.moves.len() >= self.first_move_index);
        &self.moves[self.first_move_index..]
    }

    /// Returns the current move list as a mutable slice.
    #[inline]
    pub fn list_mut(&mut self) -> &mut [Move] {
        debug_assert!(self.moves.len() >= self.first_move_index);
        &mut self.moves[self.first_move_index..]
    }
}

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

    #[should_panic]
    #[test]
    fn move_stack_pull_panic() {
        let mut s = MoveStack::new();
        s.pull(0);
    }

    #[test]
    fn move_stack() {
        let cr = CastlingRights::new(0);
        let m = Move::new(MOVE_NORMAL, E2, E4, 0, PIECE_NONE, PAWN, cr, 8, 0);
        let mut s = MoveStack::new();
        assert_eq!(s.ply(), 0);
        assert!(s.pull_best().is_none());
        s.save();
        assert_eq!(s.ply(), 1);
        s.push(m);
        assert_eq!(s.pull(0), m);
        assert!(s.pull_best().is_none());
        s.restore();
        assert!(s.pull_best().is_none());
        assert_eq!(s.list().len(), 0);
        assert!(s.pop().is_none());
        assert!(s.pull_move(m.digest()).is_none());
        s.push(m);
        s.push(m);
        assert_eq!(s.list().len(), 2);
        assert_eq!(s.pop().unwrap(), m);
        assert_eq!(s.list().len(), 1);
        s.push(m);
        assert_eq!(s.pull_move(m.digest()).unwrap(), m);
        assert_eq!(s.list().len(), 1);
        s.push(m);
        assert_eq!(s.list().iter().count(), 2);
        s.save();
        s.push(m);
        s.restore();
        assert_eq!(s.pull_best().unwrap(), m);
        assert_eq!(s.pull_best().unwrap(), m);
        assert!(s.pull_best().is_none());
        assert_eq!(s.ply(), 0);
        s.push(m);
        s.clear();
        assert_eq!(s.ply(), 0);
        assert_eq!(s.list().len(), 0);
        s.save();
        s.save();
        s.push(m);
        assert_eq!(s.ply(), 2);
        s.clear_all();
        assert_eq!(s.ply(), 0);
        assert_eq!(s.list().len(), 0);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_install"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Ben Eills <ben@beneills.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

mod mode;

#[macro_use]
extern crate uucore;

use std::fs;
use std::path::{Path, PathBuf};
use std::result::Result;

static NAME: &'static str = "install";
static SUMMARY: &'static str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
 DIRECTORY, while setting permission modes and owner/group";
static LONG_HELP: &'static str = "";

const DEFAULT_MODE: u32 = 755;

#[allow(dead_code)]
pub struct Behaviour {
    main_function: MainFunction,
    specified_mode: Option<u32>,
    suffix: String,
    verbose: bool
}

#[derive(Clone, Eq, PartialEq)]
pub enum MainFunction {
    /// Create directories
    Directory,
    /// Install files to locations (primary functionality)
    Standard
}

impl Behaviour {
    /// Determine the mode for chmod after copy.
    pub fn mode(&self) -> u32 {
        match self.specified_mode {
            Some(x) => x,
            None => DEFAULT_MODE
        }
    }
}

/// Main install utility function, called from main.rs.
///
/// Returns a program return code.
///
pub fn uumain(args: Vec<String>) -> i32 {
    let matches = parse_opts(args);

    if let Err(s) = check_unimplemented(&matches) {
        show_error!("Unimplemented feature: {}", s);
        return 2;
    }

    let behaviour = match behaviour(&matches) {
        Ok(x) => x,
        Err(ret) => {
            return ret;
        }
    };

    let paths: Vec<PathBuf> = {
        fn string_to_path<'a>(s: &'a String) -> &'a Path {
            Path::new(s)
        };
        let to_owned = |p: &Path| p.to_owned();
        let arguments = matches.free.iter().map(string_to_path);

        arguments.map(to_owned).collect()
    };

    match behaviour.main_function {
        MainFunction::Directory => {
            directory(&paths[..], behaviour)
        },
        MainFunction::Standard => {
            standard(&paths[..], behaviour)
        }
    }
}

/// Build a specification of the command line.
///
/// Returns a getopts::Options struct.
///
fn parse_opts(args: Vec<String>) -> getopts::Matches {
    let syntax = format!("SOURCE DEST
 {} SOURCE... DIRECTORY", NAME);
     new_coreopts!(&syntax, SUMMARY, LONG_HELP)
    // TODO implement flag
        .optflagopt("",  "backup", "(unimplemented) make a backup of each existing destination\n \
                                    file", "CONTROL")
    // TODO implement flag
        .optflag("b", "", "(unimplemented) like --backup but does not accept an argument")
    // TODO implement flag
        .optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
                                  files, and in some cases, do not modify the destination at all")
        .optflag("d", "directory", "treat all arguments as directory names\n \
                                    create all components of the specified directories")
    // TODO implement flag
        .optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
                           last, then copy SOURCE to DEST")
    // TODO implement flag
        .optflagopt("g", "group", "(unimplemented) set group ownership, instead of process'\n \
                                   current group", "GROUP")
        .optflagopt("m", "mode", "set permission mode (as in chmod), instead\n \
                                  of rwxr-xr-x", "MODE")
    // TODO implement flag
        .optflagopt("o", "owner", "(unimplemented) set ownership (super-user only)",
                    "OWNER")
    // TODO implement flag
        .optflag("p", "preserve-timestamps", "(unimplemented) apply access/modification times\n \
                                              of SOURCE files to corresponding destination files")
    // TODO implement flag
        .optflag("s", "strip", "(unimplemented) strip symbol tables")
    // TODO implement flag
        .optflagopt("", "strip-program", "(unimplemented) program used to strip binaries",
                    "PROGRAM")
    // TODO implement flag
        .optopt("S", "suffix", "(unimplemented) override the usual backup suffix", "SUFFIX")
    // TODO implement flag
        .optopt("t", "target-directory", "(unimplemented) move all SOURCE arguments into\n \
                                          DIRECTORY", "DIRECTORY")
    // TODO implement flag
        .optflag("T", "no-target-directory", "(unimplemented) treat DEST as a normal file")
        .optflag("v", "verbose", "explain what is being done")
    // TODO implement flag
        .optflag("P", "preserve-context", "(unimplemented) preserve security context")
    // TODO implement flag
        .optflagopt("Z", "context", "(unimplemented) set security context of files and\n \
                                     directories", "CONTEXT")
        .parse(args)
}

/// Check for unimplemented command line arguments.
///
/// Either return the degenerate Ok value, or an Err with string.
///
/// # Errors
///
/// Error datum is a string of the unimplemented argument.
///
fn check_unimplemented(matches: &getopts::Matches) -> Result<(), &str> {
    if matches.opt_present("backup") {
        Err("--backup")
    } else if matches.opt_present("b") {
        Err("-b")
    } else if matches.opt_present("compare") {
        Err("--compare, -C")
    } else if matches.opt_present("D") {
        Err("-D")
    } else if matches.opt_present("group") {
        Err("--group, -g")
    } else if matches.opt_present("owner") {
        Err("--owner, -o")
    } else if matches.opt_present("preserve-timestamps") {
        Err("--preserve-timestamps, -p")
    } else if matches.opt_present("strip") {
        Err("--strip, -s")
    } else if matches.opt_present("strip-program") {
        Err("--strip-program")
    } else if matches.opt_present("suffix") {
        Err("--suffix, -S")
    } else if matches.opt_present("target-directory") {
        Err("--target-directory, -t")
    } else if matches.opt_present("no-target-directory") {
        Err("--no-target-directory, -T")
    } else if matches.opt_present("preserve-context") {
        Err("--preserve-context, -P")
    } else if matches.opt_present("context") {
        Err("--context, -Z")
    } else {
        Ok(())
    }
}

/// Determine behaviour, given command line arguments.
///
/// If successful, returns a filled-out Behaviour struct.
///
/// # Errors
///
/// In event of failure, returns an integer intended as a program return code.
///
fn behaviour(matches: &getopts::Matches) -> Result<Behaviour, i32> {
    let main_function = if matches.opt_present("directory") {
        MainFunction::Directory
    } else {
        MainFunction::Standard
    };

    let considering_dir: bool = MainFunction::Directory == main_function;

    let specified_mode: Option<u32> = if matches.opt_present("mode") {
        match matches.opt_str("mode") {
            Some(x) => {
                match mode::parse(&x[..], considering_dir) {
                    Ok(y) => Some(y),
                    Err(err) => {
                        show_error!("Invalid mode string: {}", err);
                        return Err(1);
                    }
                }
            },
            None => {
                show_error!("option '--mode' requires an argument\n \
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        None
    };

    let backup_suffix = if matches.opt_present("suffix") {
        match matches.opt_str("suffix") {
            Some(x) => x,
            None => {
                show_error!("option '--suffix' requires an argument\n\
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        "~".to_owned()
    };

    Ok(Behaviour {
        main_function: main_function,
        specified_mode: specified_mode,
        suffix: backup_suffix,
        verbose: matches.opt_present("v"),
    })
}

/// Creates directories.
///
/// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'.
///
/// Returns an integer intended as a program return code.
///
fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 1 {
        println!("{} with -d requires at least one argument.", NAME);
        1
    } else {
        let mut all_successful = true;

        for directory in paths.iter() {
            let path = directory.as_path();

            if path.exists() {
                show_info!("cannot create directory '{}': File exists", path.display());
                all_successful = false;
            }

            if let Err(e) = fs::create_dir(directory) {
                show_info!("{}: {}", path.display(), e.to_string());
                all_successful = false;
            }

            if mode::chmod(&path, b.mode()).is_err() {
                all_successful = false;
            }

            if b.verbose {
                show_info!("created directory '{}'", path.display());
            }
        }
        if all_successful { 0 } else { 1 }
    }
}

/// Perform an install, given a list of paths and behaviour.
///
/// Returns an integer intended as a program return code.
///
fn standard(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 2 {
        println!("{} requires at least 2 arguments.", NAME);
        1
    } else {
        let sources = &paths[0..paths.len() - 1];
        let target_directory = &paths[paths.len() - 1];

        copy_files_into_dir(sources, target_directory, &b)
    }
}

/// Copy some files into a directory.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            sourcepath.display());

                all_successful = false;
                continue;
            }
        };

        if copy(sourcepath, &targetpath, b).is_err() {
            all_successful = false;
        }
    };
    if all_successful { 0 } else { 1 }
}

/// Copy one file to a new location, changing metadata.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<(), ()> {
    let io_result = fs::copy(from, to);

    if let Err(err) = io_result {
        show_error!("install: cannot install ‘{}’ to ‘{}’: {}",
                    from.display(), to.display(), err);
        return Err(());
    }

    if mode::chmod(&to, b.mode()).is_err() {
        return Err(());
    }

    if b.verbose {
        show_info!("'{}' -> '{}'", from.display(), to.display());
    }

    Ok(())
}
<commit_msg>install: ignore -c option for compatibility<commit_after>#![crate_name = "uu_install"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Ben Eills <ben@beneills.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

mod mode;

#[macro_use]
extern crate uucore;

use std::fs;
use std::path::{Path, PathBuf};
use std::result::Result;

static NAME: &'static str = "install";
static SUMMARY: &'static str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
 DIRECTORY, while setting permission modes and owner/group";
static LONG_HELP: &'static str = "";

const DEFAULT_MODE: u32 = 755;

#[allow(dead_code)]
pub struct Behaviour {
    main_function: MainFunction,
    specified_mode: Option<u32>,
    suffix: String,
    verbose: bool
}

#[derive(Clone, Eq, PartialEq)]
pub enum MainFunction {
    /// Create directories
    Directory,
    /// Install files to locations (primary functionality)
    Standard
}

impl Behaviour {
    /// Determine the mode for chmod after copy.
    pub fn mode(&self) -> u32 {
        match self.specified_mode {
            Some(x) => x,
            None => DEFAULT_MODE
        }
    }
}

/// Main install utility function, called from main.rs.
///
/// Returns a program return code.
///
pub fn uumain(args: Vec<String>) -> i32 {
    let matches = parse_opts(args);

    if let Err(s) = check_unimplemented(&matches) {
        show_error!("Unimplemented feature: {}", s);
        return 2;
    }

    let behaviour = match behaviour(&matches) {
        Ok(x) => x,
        Err(ret) => {
            return ret;
        }
    };

    let paths: Vec<PathBuf> = {
        fn string_to_path<'a>(s: &'a String) -> &'a Path {
            Path::new(s)
        };
        let to_owned = |p: &Path| p.to_owned();
        let arguments = matches.free.iter().map(string_to_path);

        arguments.map(to_owned).collect()
    };

    match behaviour.main_function {
        MainFunction::Directory => {
            directory(&paths[..], behaviour)
        },
        MainFunction::Standard => {
            standard(&paths[..], behaviour)
        }
    }
}

/// Build a specification of the command line.
///
/// Returns a getopts::Options struct.
///
fn parse_opts(args: Vec<String>) -> getopts::Matches {
    let syntax = format!("SOURCE DEST
 {} SOURCE... DIRECTORY", NAME);
     new_coreopts!(&syntax, SUMMARY, LONG_HELP)
    // TODO implement flag
        .optflagopt("",  "backup", "(unimplemented) make a backup of each existing destination\n \
                                    file", "CONTROL")
    // TODO implement flag
        .optflag("b", "", "(unimplemented) like --backup but does not accept an argument")
        .optflag("c", "", "ignored")
    // TODO implement flag
        .optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
                                  files, and in some cases, do not modify the destination at all")
        .optflag("d", "directory", "treat all arguments as directory names\n \
                                    create all components of the specified directories")
    // TODO implement flag
        .optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
                           last, then copy SOURCE to DEST")
    // TODO implement flag
        .optflagopt("g", "group", "(unimplemented) set group ownership, instead of process'\n \
                                   current group", "GROUP")
        .optflagopt("m", "mode", "set permission mode (as in chmod), instead\n \
                                  of rwxr-xr-x", "MODE")
    // TODO implement flag
        .optflagopt("o", "owner", "(unimplemented) set ownership (super-user only)",
                    "OWNER")
    // TODO implement flag
        .optflag("p", "preserve-timestamps", "(unimplemented) apply access/modification times\n \
                                              of SOURCE files to corresponding destination files")
    // TODO implement flag
        .optflag("s", "strip", "(unimplemented) strip symbol tables")
    // TODO implement flag
        .optflagopt("", "strip-program", "(unimplemented) program used to strip binaries",
                    "PROGRAM")
    // TODO implement flag
        .optopt("S", "suffix", "(unimplemented) override the usual backup suffix", "SUFFIX")
    // TODO implement flag
        .optopt("t", "target-directory", "(unimplemented) move all SOURCE arguments into\n \
                                          DIRECTORY", "DIRECTORY")
    // TODO implement flag
        .optflag("T", "no-target-directory", "(unimplemented) treat DEST as a normal file")
        .optflag("v", "verbose", "explain what is being done")
    // TODO implement flag
        .optflag("P", "preserve-context", "(unimplemented) preserve security context")
    // TODO implement flag
        .optflagopt("Z", "context", "(unimplemented) set security context of files and\n \
                                     directories", "CONTEXT")
        .parse(args)
}

/// Check for unimplemented command line arguments.
///
/// Either return the degenerate Ok value, or an Err with string.
///
/// # Errors
///
/// Error datum is a string of the unimplemented argument.
///
fn check_unimplemented(matches: &getopts::Matches) -> Result<(), &str> {
    if matches.opt_present("backup") {
        Err("--backup")
    } else if matches.opt_present("b") {
        Err("-b")
    } else if matches.opt_present("compare") {
        Err("--compare, -C")
    } else if matches.opt_present("D") {
        Err("-D")
    } else if matches.opt_present("group") {
        Err("--group, -g")
    } else if matches.opt_present("owner") {
        Err("--owner, -o")
    } else if matches.opt_present("preserve-timestamps") {
        Err("--preserve-timestamps, -p")
    } else if matches.opt_present("strip") {
        Err("--strip, -s")
    } else if matches.opt_present("strip-program") {
        Err("--strip-program")
    } else if matches.opt_present("suffix") {
        Err("--suffix, -S")
    } else if matches.opt_present("target-directory") {
        Err("--target-directory, -t")
    } else if matches.opt_present("no-target-directory") {
        Err("--no-target-directory, -T")
    } else if matches.opt_present("preserve-context") {
        Err("--preserve-context, -P")
    } else if matches.opt_present("context") {
        Err("--context, -Z")
    } else {
        Ok(())
    }
}

/// Determine behaviour, given command line arguments.
///
/// If successful, returns a filled-out Behaviour struct.
///
/// # Errors
///
/// In event of failure, returns an integer intended as a program return code.
///
fn behaviour(matches: &getopts::Matches) -> Result<Behaviour, i32> {
    let main_function = if matches.opt_present("directory") {
        MainFunction::Directory
    } else {
        MainFunction::Standard
    };

    let considering_dir: bool = MainFunction::Directory == main_function;

    let specified_mode: Option<u32> = if matches.opt_present("mode") {
        match matches.opt_str("mode") {
            Some(x) => {
                match mode::parse(&x[..], considering_dir) {
                    Ok(y) => Some(y),
                    Err(err) => {
                        show_error!("Invalid mode string: {}", err);
                        return Err(1);
                    }
                }
            },
            None => {
                show_error!("option '--mode' requires an argument\n \
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        None
    };

    let backup_suffix = if matches.opt_present("suffix") {
        match matches.opt_str("suffix") {
            Some(x) => x,
            None => {
                show_error!("option '--suffix' requires an argument\n\
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        "~".to_owned()
    };

    Ok(Behaviour {
        main_function: main_function,
        specified_mode: specified_mode,
        suffix: backup_suffix,
        verbose: matches.opt_present("v"),
    })
}

/// Creates directories.
///
/// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'.
///
/// Returns an integer intended as a program return code.
///
fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 1 {
        println!("{} with -d requires at least one argument.", NAME);
        1
    } else {
        let mut all_successful = true;

        for directory in paths.iter() {
            let path = directory.as_path();

            if path.exists() {
                show_info!("cannot create directory '{}': File exists", path.display());
                all_successful = false;
            }

            if let Err(e) = fs::create_dir(directory) {
                show_info!("{}: {}", path.display(), e.to_string());
                all_successful = false;
            }

            if mode::chmod(&path, b.mode()).is_err() {
                all_successful = false;
            }

            if b.verbose {
                show_info!("created directory '{}'", path.display());
            }
        }
        if all_successful { 0 } else { 1 }
    }
}

/// Perform an install, given a list of paths and behaviour.
///
/// Returns an integer intended as a program return code.
///
fn standard(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 2 {
        println!("{} requires at least 2 arguments.", NAME);
        1
    } else {
        let sources = &paths[0..paths.len() - 1];
        let target_directory = &paths[paths.len() - 1];

        copy_files_into_dir(sources, target_directory, &b)
    }
}

/// Copy some files into a directory.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            sourcepath.display());

                all_successful = false;
                continue;
            }
        };

        if copy(sourcepath, &targetpath, b).is_err() {
            all_successful = false;
        }
    };
    if all_successful { 0 } else { 1 }
}

/// Copy one file to a new location, changing metadata.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<(), ()> {
    let io_result = fs::copy(from, to);

    if let Err(err) = io_result {
        show_error!("install: cannot install ‘{}’ to ‘{}’: {}",
                    from.display(), to.display(), err);
        return Err(());
    }

    if mode::chmod(&to, b.mode()).is_err() {
        return Err(());
    }

    if b.verbose {
        show_info!("'{}' -> '{}'", from.display(), to.display());
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::slice;
use std::mem;
use std::fmt;
use num;
use approx;
use channel::{NormalBoundedChannel, ColorChannel, NormalChannelScalar, ChannelFormatCast,
              ChannelCast, PosNormalChannelScalar, PosNormalBoundedChannel};
use color::{Color, FromTuple, Invert, Bounded, Lerp, Flatten};

use ycbcr::model::YCbCrModel;
use ycbcr::YCbCr;
use rgb::Rgb;

pub enum OutOfGamutMode {
    Preserve,
    Clip,
}

pub struct YCbCrTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct BareYCbCr<T> {
    luma: PosNormalBoundedChannel<T>,
    cb: NormalBoundedChannel<T>,
    cr: NormalBoundedChannel<T>,
}

impl<T> BareYCbCr<T>
    where T: NormalChannelScalar + PosNormalChannelScalar
{
    pub fn from_channels(luma: T, cb: T, cr: T) -> Self {
        BareYCbCr {
            luma: PosNormalBoundedChannel::new(luma),
            cb: NormalBoundedChannel::new(cb),
            cr: NormalBoundedChannel::new(cr),
        }
    }

    impl_color_color_cast_square!(BareYCbCr {luma, cb, cr},
        chan_traits={PosNormalChannelScalar, NormalChannelScalar});

    pub fn luma(&self) -> T {
        self.luma.0.clone()
    }
    pub fn cb(&self) -> T {
        self.cb.0.clone()
    }
    pub fn cr(&self) -> T {
        self.cr.0.clone()
    }
    pub fn luma_mut(&mut self) -> &mut T {
        &mut self.luma.0
    }
    pub fn cb_mut(&mut self) -> &mut T {
        &mut self.cb.0
    }
    pub fn cr_mut(&mut self) -> &mut T {
        &mut self.cr.0
    }
    pub fn set_luma(&mut self, val: T) {
        self.luma.0 = val;
    }
    pub fn set_cb(&mut self, val: T) {
        self.cb.0 = val;
    }
    pub fn set_cr(&mut self, val: T) {
        self.cr.0 = val;
    }

    pub fn with_model<M>(self, model: M) -> YCbCr<T, M>
        where M: YCbCrModel<T>
    {
        YCbCr::from_color_and_model(self, model)
    }
}

impl<T> Color for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    type Tag = YCbCrTag;
    type ChannelsTuple = (T, T, T);

    #[inline]
    fn num_channels() -> u32 {
        3
    }

    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.luma.0, self.cb.0, self.cr.0)
    }
}

impl<T> FromTuple for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        BareYCbCr::from_channels(values.0, values.1, values.2)
    }
}

impl<T> Invert for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    impl_color_invert!(BareYCbCr {luma, cb, cr});
}

impl<T> Bounded for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    impl_color_bounded!(BareYCbCr {luma, cb, cr});
}

impl<T> Lerp for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + Lerp
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(BareYCbCr {luma, cb, cr});
}

impl<T> Flatten for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(BareYCbCr<T> {luma:PosNormalBoundedChannel - 0,
        cb:NormalBoundedChannel - 1, cr:NormalBoundedChannel - 2});
}

impl<T> approx::ApproxEq for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + approx::ApproxEq,
          T::Epsilon: Clone
{
    impl_approx_eq!({luma, cb, cr});
}

impl<T> Default for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + num::Zero
{
    impl_color_default!(BareYCbCr {luma:PosNormalBoundedChannel,
        cb:NormalBoundedChannel,
        cr:NormalBoundedChannel});
}

impl<T> fmt::Display for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "YCbCr({}, {}, {})", self.luma, self.cb, self.cr)
    }
}

impl<T> BareYCbCr<T>
    where T: NormalChannelScalar + PosNormalChannelScalar + num::NumCast
{
    pub fn from_rgb_and_model<M: YCbCrModel<T>>(from: &Rgb<T>, model: &M) -> Self {
        let transform = model.forward_transform();
        let shift = model.shift();

        let (y, cb, cr) = transform.transform_vector(from.clone().to_tuple());

        BareYCbCr::from_channels(y + shift.0, cb + shift.1, cr + shift.2)
    }

    pub fn to_rgb<M: YCbCrModel<T>>(&self, model: &M, out_of_gamut_mode: OutOfGamutMode) -> Rgb<T> {
        let transform = model.inverse_transform();
        let shift = model.shift();

        let (i1, i2, i3) = self.clone().to_tuple();
        let shifted_color =
            (num::cast::<_, f64>(i1).unwrap() - num::cast::<_, f64>(shift.0).unwrap(),
             num::cast::<_, f64>(i2).unwrap() - num::cast::<_, f64>(shift.1).unwrap(),
             num::cast::<_, f64>(i3).unwrap() - num::cast::<_, f64>(shift.2).unwrap());

        let (r, g, b) = transform.transform_vector(shifted_color);

        let out = Rgb::from_channels(num::cast(r).unwrap(),
                                     num::cast(g).unwrap(),
                                     num::cast(b).unwrap());

        match out_of_gamut_mode {
            OutOfGamutMode::Preserve => out,
            OutOfGamutMode::Clip => out.normalize(),
        }
    }
}
<commit_msg>Documented `ycbcr::bare_ycbcr` module.<commit_after>//! Defines `BareYCbCr` for YCbCr colors that don't store their model.

use std::slice;
use std::mem;
use std::fmt;
use num;
use approx;
use channel::{NormalBoundedChannel, ColorChannel, NormalChannelScalar, ChannelFormatCast,
              ChannelCast, PosNormalChannelScalar, PosNormalBoundedChannel};
use color::{Color, FromTuple, Invert, Bounded, Lerp, Flatten};

use ycbcr::model::YCbCrModel;
use ycbcr::YCbCr;
use rgb::Rgb;

/// Methods for handling out of gamut colors when converting to Rgb.
///
/// These are used by the `to_rgb` method. Using `TryFromColor` will instead
/// return `None` any time an out of gamut value is produced.
pub enum OutOfGamutMode {
    /// Return the exact result of the transformation.
    ///
    /// This can result in channels outside the normal range
    /// (eg. less than 0 or greater than 1).
    Preserve,
    /// Clip any out-of-bounds channels to their minimum or maximum value (0.0 or 1.0).
    ///
    /// For example, -0.2 would go to 0.0 and 2.0 would go to 1.
    Clip,
}

/// A unit struct for identifying and constraining YCbCr colors in generic code.
pub struct YCbCrTag;

/// A YCbCr color that does not know its model.
///
/// `BareYCbCr` is used internally to implement `YCbCr` and is provided as
/// a separate type for performance reasons; generally, the use of `YCbCr` is preferred.
/// It is "bare" in the sense that it does not store the model information along with the
/// channel information. This makes it less smart, but can save memory when used with custom
/// models.
///
/// When using a custom model, `YCbCr` must store a reference to the model along with its
/// channel values. This can increase the memory footprint significantly, but gives greater
/// safety and convenience as well as forbidding illogical conversions and comparisons.
/// It is therefore only advised to use this when the extra memory consumption
/// has show to be an issue.
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct BareYCbCr<T> {
    luma: PosNormalBoundedChannel<T>,
    cb: NormalBoundedChannel<T>,
    cr: NormalBoundedChannel<T>,
}

impl<T> BareYCbCr<T>
    where T: NormalChannelScalar + PosNormalChannelScalar
{
    /// Construct a `BareYCbCr` from channel values.
    pub fn from_channels(luma: T, cb: T, cr: T) -> Self {
        BareYCbCr {
            luma: PosNormalBoundedChannel::new(luma),
            cb: NormalBoundedChannel::new(cb),
            cr: NormalBoundedChannel::new(cr),
        }
    }

    impl_color_color_cast_square!(BareYCbCr {luma, cb, cr},
        chan_traits={PosNormalChannelScalar, NormalChannelScalar});

    /// Return the luma (Y') channel.
    pub fn luma(&self) -> T {
        self.luma.0.clone()
    }
    /// Return the Cb channel.
    pub fn cb(&self) -> T {
        self.cb.0.clone()
    }
    /// Return the Cr channel.
    pub fn cr(&self) -> T {
        self.cr.0.clone()
    }
    /// Return a mutable reference to the luma (Y') channel.
    pub fn luma_mut(&mut self) -> &mut T {
        &mut self.luma.0
    }
    /// Return a mutable reference to the Cb channel.
    pub fn cb_mut(&mut self) -> &mut T {
        &mut self.cb.0
    }
    /// Return a mutable reference to the Cr channel.
    pub fn cr_mut(&mut self) -> &mut T {
        &mut self.cr.0
    }
    /// Set the luma (Y') channel to a value.
    pub fn set_luma(&mut self, val: T) {
        self.luma.0 = val;
    }
    /// Set the Cb channel to a value.
    pub fn set_cb(&mut self, val: T) {
        self.cb.0 = val;
    }
    /// Set the Cr channel to a value.
    pub fn set_cr(&mut self, val: T) {
        self.cr.0 = val;
    }

    /// Construct a new `YCbCr` object from `self` and a model.
    ///
    /// Equivalent to constructing the `YCbCr` object directly:
    ///
    /// ```
    /// # use simple_color::ycbcr::*;
    /// let c = BareYCbCr::from_channels(0.5, 0.3, 0.2).with_model(JpegModel);
    /// assert_eq!(c, YCbCrJpeg::from_channels(0.5, 0.3, 0.2));
    /// ```
    pub fn with_model<M>(self, model: M) -> YCbCr<T, M>
        where M: YCbCrModel<T>
    {
        YCbCr::from_color_and_model(self, model)
    }
}

impl<T> Color for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    type Tag = YCbCrTag;
    type ChannelsTuple = (T, T, T);

    #[inline]
    fn num_channels() -> u32 {
        3
    }

    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.luma.0, self.cb.0, self.cr.0)
    }
}

impl<T> FromTuple for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        BareYCbCr::from_channels(values.0, values.1, values.2)
    }
}

impl<T> Invert for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    impl_color_invert!(BareYCbCr {luma, cb, cr});
}

impl<T> Bounded for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    impl_color_bounded!(BareYCbCr {luma, cb, cr});
}

impl<T> Lerp for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + Lerp
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(BareYCbCr {luma, cb, cr});
}

impl<T> Flatten for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(BareYCbCr<T> {luma:PosNormalBoundedChannel - 0,
        cb:NormalBoundedChannel - 1, cr:NormalBoundedChannel - 2});
}

impl<T> approx::ApproxEq for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + approx::ApproxEq,
          T::Epsilon: Clone
{
    impl_approx_eq!({luma, cb, cr});
}

impl<T> Default for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + num::Zero
{
    impl_color_default!(BareYCbCr {luma:PosNormalBoundedChannel,
        cb:NormalBoundedChannel,
        cr:NormalBoundedChannel});
}

impl<T> fmt::Display for BareYCbCr<T>
    where T: PosNormalChannelScalar + NormalChannelScalar + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "YCbCr({}, {}, {})", self.luma, self.cb, self.cr)
    }
}

impl<T> BareYCbCr<T>
    where T: NormalChannelScalar + PosNormalChannelScalar + num::NumCast
{
    /// Construct a `BareYCbCr` by converting from an Rgb `value`.
    ///
    /// `model` is only used within the conversion, it is up to the user
    /// to remember which model any `BareYCbCr` is using.
    pub fn from_rgb_and_model<M: YCbCrModel<T>>(from: &Rgb<T>, model: &M) -> Self {
        let transform = model.forward_transform();
        let shift = model.shift();

        let (y, cb, cr) = transform.transform_vector(from.clone().to_tuple());

        BareYCbCr::from_channels(y + shift.0, cb + shift.1, cr + shift.2)
    }

    /// Convert from YCbCr to Rgb.
    ///
    /// # Params
    ///
    /// * model - The model to use for the conversion. Note that this does not change the model
    ///   of the color being converted. If you convert to YCbCr from Rgb and convert back under a
    ///   different model, the resulting colors will be different.
    /// * out_of_gamut_mode - How to handle colors that are out of gamut in `Rgb`. See
    ///   [OutOfGamutMode](enum.OutOfGamutMode.html) for a description the options.
    pub fn to_rgb<M: YCbCrModel<T>>(&self, model: &M, out_of_gamut_mode: OutOfGamutMode) -> Rgb<T> {
        let transform = model.inverse_transform();
        let shift = model.shift();

        let (i1, i2, i3) = self.clone().to_tuple();
        let shifted_color =
            (num::cast::<_, f64>(i1).unwrap() - num::cast::<_, f64>(shift.0).unwrap(),
             num::cast::<_, f64>(i2).unwrap() - num::cast::<_, f64>(shift.1).unwrap(),
             num::cast::<_, f64>(i3).unwrap() - num::cast::<_, f64>(shift.2).unwrap());

        let (r, g, b) = transform.transform_vector(shifted_color);

        let out = Rgb::from_channels(num::cast(r).unwrap(),
                                     num::cast(g).unwrap(),
                                     num::cast(b).unwrap());

        match out_of_gamut_mode {
            OutOfGamutMode::Preserve => out,
            OutOfGamutMode::Clip => out.normalize(),
        }
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::ffi::OsString;
use std::ops::Range;
use std::str;

/// A `struct` useful for matching borrowed `str`s.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct StrInput<'a> {
    str_ref: &'a str
}

#[inline]
unsafe fn line_col(source: &str, pos: usize) -> (usize, usize) {
    if pos > source.len() {
        panic!("position out of bounds");
    }

    let mut pos = pos;
    let slice = &source[..pos];
    let mut chars = slice.chars().peekable();

    let mut line_col = (1, 1);

    while pos != 0 {
        match chars.next() {
            Some('\r') => {
                if let Some(&'\n') = chars.peek() {
                    chars.next();

                    if pos == 1 {
                        pos -= 1;
                    } else {
                        pos -= 2;
                    }

                    line_col = (line_col.0 + 1, 1);
                } else {
                    pos -= 1;
                    line_col = (line_col.0, line_col.1 + 1);
                }
            }
            Some('\n') => {
                pos -= 1;
                line_col = (line_col.0 + 1, 1);
            }
            Some(c) => {
                pos -= c.len_utf8();
                line_col = (line_col.0, line_col.1 + 1);
            }
            None => unreachable!()
        }
    }

    line_col
}

#[inline]
unsafe fn line_of(source: &str, pos: usize) -> &str {
    if pos > source.len() {
        panic!("position out of bounds");
    }

    let start = if pos == 0 {
        0
    } else {
        let start = source.char_indices()
                          .rev()
                          .skip_while(|&(i, _)| i >= pos)
                          .find(|&(_, c)| c == '\n');
        match start {
            Some((i, _)) => i + 1,
            None => 0
        }
    };

    let end = if source.len() == 0 {
        0
    } else if pos == source.len() - 1 {
        let mut end = source.len();

        if end > 0 && source.slice_unchecked(end - 1, end) == "\n" {
            end -= 1;
        }
        if end > 0 && source.slice_unchecked(end - 1, end) == "\r" {
            end -= 1;
        }

        end
    } else {
        let end = source.char_indices()
                        .skip_while(|&(i, _)| i < pos)
                        .find(|&(_, c)| c == '\n');
        let mut end = match end {
            Some((i, _)) => i,
            None => source.len()
        };

        if end > 0 && source.slice_unchecked(end - 1, end) == "\r" {
            end -= 1;
        }

        end
    };

    source.slice_unchecked(start, end)
}

#[inline]
unsafe fn skip(source: &str, n: usize, pos: usize) -> Option<usize> {
    let mut len = 0;
    let mut chars = source.slice_unchecked(pos, source.len()).chars();

    for _ in 0..n {
        if let Some(c) = chars.next() {
            len += c.len_utf8();
        } else {
            return None;
        }
    }

    Some(len)
}

#[inline]
unsafe fn match_string(source: &str, string: &str, pos: usize) -> bool {
    let to = pos + string.len();

    if to <= source.len() {
        let slice = source.slice_unchecked(pos, to);
        slice == string
    } else {
        false
    }
}

#[inline]
unsafe fn match_insensitive(source: &str, string: &str, pos: usize) -> bool {
    let slice = source.slice_unchecked(pos, source.len());

    if slice.is_char_boundary(string.len()) {
        let slice = slice.slice_unchecked(0, string.len());
        slice.eq_ignore_ascii_case(string)
    } else {
        false
    }
}

#[inline]
unsafe fn match_range(source: &str, range: Range<char>, pos: usize) -> Option<usize> {
    let slice = source.slice_unchecked(pos, source.len());

    if let Some(char) = slice.chars().next() {
        if range.start <= char && char <= range.end {
            Some(char.len_utf8())
        } else {
            None
        }
    } else {
        None
    }
}

impl<'a> StrInput<'a> {
    /// Creates a new `StrInput` from a `&str`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::inputs::{StrInput};
    /// let input = StrInput::new("asd");
    ///
    /// assert_eq!(input.len(), 3);
    /// ```
    pub fn new(source: &'a str) -> StrInput<'a> {
        StrInput { str_ref: source }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.str_ref.len()
    }

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

    #[inline]
    pub fn file_name(&self) -> Option<OsString> {
        None
    }

    #[inline]
    pub unsafe fn slice(&self, start: usize, end: usize) -> &'a str {
        self.str_ref.slice_unchecked(start, end)
    }

    pub unsafe fn line_col(&self, pos: usize) -> (usize, usize) {
        line_col(self.str_ref, pos)
    }

    pub unsafe fn line_of(&self, pos: usize) -> &'a str {
        line_of(self.str_ref, pos)
    }

    #[inline]
    pub unsafe fn skip(&self, n: usize, pos: usize) -> Option<usize> {
        skip(self.str_ref, n, pos)
    }

    #[inline]
    pub unsafe fn match_string(&self, string: &str, pos: usize) -> bool {
        match_string(self.str_ref, string, pos)
    }

    #[inline]
    pub unsafe fn match_insensitive(&self, string: &str, pos: usize) -> bool {
        match_insensitive(self.str_ref, string, pos)
    }

    #[inline]
    pub unsafe fn match_range(&self, range: Range<char>, pos: usize) -> Option<usize> {
        match_range(self.str_ref, range, pos)
    }
}

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

    #[test]
    fn empty() {
        let input2 = StrInput::new("");

        unsafe {
            assert!(input2.is_empty());
            assert!(input2.match_string("", 0));
            assert!(!input2.match_string("a", 0));
        }
    }

    #[test]
    fn parts() {
        let input2 = StrInput::new("asdasdf");

        unsafe {
            assert!(!input2.is_empty());
            assert!(input2.match_string("asd", 0));
            assert!(input2.match_string("asdf", 3));
        }
    }

    #[test]
    fn len() {
        assert_eq!(StrInput::new("asdasdf").len(), 7);
    }

    #[test]
    fn slice() {
        let input2 = StrInput::new("asdasdf");

        unsafe {
            assert_eq!(input2.slice(1, 3), "sd");
        }
    }

    #[test]
    fn slice_lifetime() {
        let string: String = "asdasdf".to_owned();

        let slice: &str = {
            let input2 = StrInput::new(&string);
            unsafe { input2.slice(1, 3) }

        };

        assert_eq!(slice, "sd");
    }

    #[test]
    fn line_col() {
        let input2 = StrInput::new("a\rb\nc\r\nd嗨");

        unsafe {
            assert_eq!(input2.line_col(0), (1, 1));
            assert_eq!(input2.line_col(1), (1, 2));
            assert_eq!(input2.line_col(2), (1, 3));
            assert_eq!(input2.line_col(3), (1, 4));
            assert_eq!(input2.line_col(4), (2, 1));
            assert_eq!(input2.line_col(5), (2, 2));
            assert_eq!(input2.line_col(6), (2, 3));
            assert_eq!(input2.line_col(7), (3, 1));
            assert_eq!(input2.line_col(8), (3, 2));
            assert_eq!(input2.line_col(11), (3, 3));
        }
    }

    #[test]
    fn line_of() {
        let input2 = StrInput::new("a\rb\nc\r\nd嗨");

        unsafe {
            assert_eq!(input2.line_of(0), "a\rb");
            assert_eq!(input2.line_of(1), "a\rb");
            assert_eq!(input2.line_of(2), "a\rb");
            assert_eq!(input2.line_of(3), "a\rb");
            assert_eq!(input2.line_of(4), "c");
            assert_eq!(input2.line_of(5), "c");
            assert_eq!(input2.line_of(6), "c");
            assert_eq!(input2.line_of(7), "d嗨");
            assert_eq!(input2.line_of(8), "d嗨");
            assert_eq!(input2.line_of(11), "d嗨");
        }
    }

    #[test]
    fn line_of_empty() {
        let input2 = StrInput::new("");

        unsafe {
            assert_eq!(input2.line_of(0), "");
        }
    }

    #[test]
    fn line_of_new_line() {
        let input2 = StrInput::new("\n");

        unsafe {
            assert_eq!(input2.line_of(0), "");
        }
    }

    #[test]
    fn line_of_between_new_line() {
        let input2 = StrInput::new("\n\n");

        unsafe {
            assert_eq!(input2.line_of(1), "");
        }
    }

    #[test]
    fn skip_empty() {
        let input2 = StrInput::new("");

        unsafe {
            assert_eq!(input2.skip(0, 0), Some(0));
            assert_eq!(input2.skip(1, 0), None);
        }
    }

    #[test]
    fn skip() {
        let input2 = StrInput::new("d嗨");

        unsafe {
            assert_eq!(input2.skip(0, 0), Some(0));
            assert_eq!(input2.skip(1, 0), Some(1));
            assert_eq!(input2.skip(1, 1), Some(3));
        }
    }

    #[test]
    fn match_range() {
        let input2 = StrInput::new("b");

        unsafe {
            assert!(input2.match_range('a'..'c', 0).is_some());
            assert!(input2.match_range('b'..'b', 0).is_some());
            assert!(input2.match_range('a'..'a', 0).is_none());
            assert!(input2.match_range('c'..'c', 0).is_none());
            assert!(input2.match_range('a'..'嗨', 0).is_some());
        }
    }

    #[test]
    fn match_insensitive() {
        let input2 = StrInput::new("AsdASdF");

        unsafe {
            assert!(input2.match_insensitive("asd", 0));
            assert!(input2.match_insensitive("asdf", 3));
        }
    }
}
<commit_msg>Compile on non-nightly too<commit_after>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::ffi::OsString;
use std::ops::Range;
use std::str;

/// A `struct` useful for matching borrowed `str`s.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct StrInput<'a> {
    str_ref: &'a str
}

#[inline]
unsafe fn line_col(source: &str, pos: usize) -> (usize, usize) {
    if pos > source.len() {
        panic!("position out of bounds");
    }

    let mut pos = pos;
    let slice = &source[..pos];
    let mut chars = slice.chars().peekable();

    let mut line_col = (1, 1);

    while pos != 0 {
        match chars.next() {
            Some('\r') => {
                if let Some(&'\n') = chars.peek() {
                    chars.next();

                    if pos == 1 {
                        pos -= 1;
                    } else {
                        pos -= 2;
                    }

                    line_col = (line_col.0 + 1, 1);
                } else {
                    pos -= 1;
                    line_col = (line_col.0, line_col.1 + 1);
                }
            }
            Some('\n') => {
                pos -= 1;
                line_col = (line_col.0 + 1, 1);
            }
            Some(c) => {
                pos -= c.len_utf8();
                line_col = (line_col.0, line_col.1 + 1);
            }
            None => unreachable!()
        }
    }

    line_col
}

#[inline]
unsafe fn line_of(source: &str, pos: usize) -> &str {
    if pos > source.len() {
        panic!("position out of bounds");
    }

    let start = if pos == 0 {
        0
    } else {
        let start = source.char_indices()
                          .rev()
                          .skip_while(|&(i, _)| i >= pos)
                          .find(|&(_, c)| c == '\n');
        match start {
            Some((i, _)) => i + 1,
            None => 0
        }
    };

    let end = if source.len() == 0 {
        0
    } else if pos == source.len() - 1 {
        let mut end = source.len();

        if end > 0 && source.slice_unchecked(end - 1, end) == "\n" {
            end -= 1;
        }
        if end > 0 && source.slice_unchecked(end - 1, end) == "\r" {
            end -= 1;
        }

        end
    } else {
        let end = source.char_indices()
                        .skip_while(|&(i, _)| i < pos)
                        .find(|&(_, c)| c == '\n');
        let mut end = match end {
            Some((i, _)) => i,
            None => source.len()
        };

        if end > 0 && source.slice_unchecked(end - 1, end) == "\r" {
            end -= 1;
        }

        end
    };

    source.slice_unchecked(start, end)
}

#[inline]
unsafe fn skip(source: &str, n: usize, pos: usize) -> Option<usize> {
    let mut len = 0;
    let mut chars = source.slice_unchecked(pos, source.len()).chars();

    for _ in 0..n {
        if let Some(c) = chars.next() {
            len += c.len_utf8();
        } else {
            return None;
        }
    }

    Some(len)
}

#[inline]
unsafe fn match_string(source: &str, string: &str, pos: usize) -> bool {
    let to = pos + string.len();

    if to <= source.len() {
        let slice = source.slice_unchecked(pos, to);
        slice == string
    } else {
        false
    }
}

#[inline]
unsafe fn match_insensitive(source: &str, string: &str, pos: usize) -> bool {
    let slice = source.slice_unchecked(pos, source.len());

    if slice.is_char_boundary(string.len()) {
        let slice = slice.slice_unchecked(0, string.len());
        slice.eq_ignore_ascii_case(string)
    } else {
        false
    }
}

#[inline]
unsafe fn match_range(source: &str, range: Range<char>, pos: usize) -> Option<usize> {
    let slice = source.slice_unchecked(pos, source.len());

    if let Some(char) = slice.chars().next() {
        if range.start <= char && char <= range.end {
            Some(char.len_utf8())
        } else {
            None
        }
    } else {
        None
    }
}

impl<'a> StrInput<'a> {
    /// Creates a new `StrInput` from a `&str`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::inputs::{StrInput};
    /// let input = StrInput::new("asd");
    ///
    /// assert_eq!(input.len(), 3);
    /// ```
    pub fn new(source: &'a str) -> StrInput<'a> {
        StrInput { str_ref: source }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.str_ref.len()
    }

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

    #[inline]
    pub fn file_name(&self) -> Option<OsString> {
        None
    }

    #[inline]
    pub unsafe fn slice(&self, start: usize, end: usize) -> &'a str {
        self.str_ref.slice_unchecked(start, end)
    }

    pub unsafe fn line_col(&self, pos: usize) -> (usize, usize) {
        line_col(self.str_ref, pos)
    }

    pub unsafe fn line_of(&self, pos: usize) -> &'a str {
        line_of(self.str_ref, pos)
    }

    #[inline]
    pub unsafe fn skip(&self, n: usize, pos: usize) -> Option<usize> {
        skip(self.str_ref, n, pos)
    }

    #[inline]
    pub unsafe fn match_string(&self, string: &str, pos: usize) -> bool {
        match_string(self.str_ref, string, pos)
    }

    #[inline]
    pub unsafe fn match_insensitive(&self, string: &str, pos: usize) -> bool {
        match_insensitive(self.str_ref, string, pos)
    }

    #[inline]
    pub unsafe fn match_range(&self, range: Range<char>, pos: usize) -> Option<usize> {
        match_range(self.str_ref, range, pos)
    }
}

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

    #[test]
    fn empty() {
        let input2 = StrInput::new("");

        unsafe {
            assert!(input2.is_empty());
            assert!(input2.match_string("", 0));
            assert!(!input2.match_string("a", 0));
        }
    }

    #[test]
    fn parts() {
        let input2 = StrInput::new("asdasdf");

        unsafe {
            assert!(!input2.is_empty());
            assert!(input2.match_string("asd", 0));
            assert!(input2.match_string("asdf", 3));
        }
    }

    #[test]
    fn len() {
        assert_eq!(StrInput::new("asdasdf").len(), 7);
    }

    #[test]
    fn slice() {
        let input2 = StrInput::new("asdasdf");

        unsafe {
            assert_eq!(input2.slice(1, 3), "sd");
        }
    }

    #[test]
    fn slice_lifetime() {
        let string: String = "asdasdf".to_owned();

        let slice: &str = {
            let input2 = StrInput::new(&string);
            unsafe { input2.slice(1, 3) }

        };

        assert_eq!(slice, "sd");
    }

    #[test]
    fn line_col() {
        let input2 = StrInput::new("a\rb\nc\r\nd嗨");

        unsafe {
            assert_eq!(input2.line_col(0), (1, 1));
            assert_eq!(input2.line_col(1), (1, 2));
            assert_eq!(input2.line_col(2), (1, 3));
            assert_eq!(input2.line_col(3), (1, 4));
            assert_eq!(input2.line_col(4), (2, 1));
            assert_eq!(input2.line_col(5), (2, 2));
            assert_eq!(input2.line_col(6), (2, 3));
            assert_eq!(input2.line_col(7), (3, 1));
            assert_eq!(input2.line_col(8), (3, 2));
            assert_eq!(input2.line_col(11), (3, 3));
        }
    }

    #[test]
    fn line_of() {
        let input2 = StrInput::new("a\rb\nc\r\nd嗨");

        unsafe {
            assert_eq!(input2.line_of(0), "a\rb");
            assert_eq!(input2.line_of(1), "a\rb");
            assert_eq!(input2.line_of(2), "a\rb");
            assert_eq!(input2.line_of(3), "a\rb");
            assert_eq!(input2.line_of(4), "c");
            assert_eq!(input2.line_of(5), "c");
            assert_eq!(input2.line_of(6), "c");
            assert_eq!(input2.line_of(7), "d嗨");
            assert_eq!(input2.line_of(8), "d嗨");
            assert_eq!(input2.line_of(11), "d嗨");
        }
    }

    #[test]
    fn line_of_empty() {
        let input2 = StrInput::new("");

        unsafe {
            assert_eq!(input2.line_of(0), "");
        }
    }

    #[test]
    fn line_of_new_line() {
        let input2 = StrInput::new("\n");

        unsafe {
            assert_eq!(input2.line_of(0), "");
        }
    }

    #[test]
    fn line_of_between_new_line() {
        let input2 = StrInput::new("\n\n");

        unsafe {
            assert_eq!(input2.line_of(1), "");
        }
    }

    #[test]
    fn skip_empty() {
        let input2 = StrInput::new("");

        unsafe {
            assert_eq!(input2.skip(0, 0), Some(0));
            assert_eq!(input2.skip(1, 0), None);
        }
    }

    #[test]
    fn skip() {
        let input2 = StrInput::new("d嗨");

        unsafe {
            assert_eq!(input2.skip(0, 0), Some(0));
            assert_eq!(input2.skip(1, 0), Some(1));
            assert_eq!(input2.skip(1, 1), Some(3));
        }
    }

    #[test]
    fn match_range() {
        let input2 = StrInput::new("b");

        unsafe {
            assert!(input2.match_range('a'..'c', 0).is_some());
            assert!(input2.match_range('b'..'b', 0).is_some());
            assert!(input2.match_range('a'..'a', 0).is_none());
            assert!(input2.match_range('c'..'c', 0).is_none());
            assert!(input2.match_range('a'..'嗨', 0).is_some());
        }
    }

    #[test]
    fn match_insensitive() {
        let input2 = StrInput::new("AsdASdF");

        unsafe {
            assert!(input2.match_insensitive("asd", 0));
            assert!(input2.match_insensitive("asdf", 3));
        }
    }
}
<|endoftext|>


<commit_before>use proc_macro2;
use syn;

use meta::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagnostic> {
    let flags =
        MetaItem::with_name(&item.attrs, "diesel").unwrap_or_else(|| MetaItem::empty("diesel"));
    let is_sized = !flags.has_flag("not_sized");

    let sql_types = MetaItem::all_with_name(&item.attrs, "sql_type");
    let any_sql_types = !sql_types.is_empty();
    let sql_types = sql_types
        .into_iter()
        .filter_map(|attr| attr.ty_value().map_err(Diagnostic::emit).ok());

    let (impl_generics, ..) = item.generics.split_for_impl();
    let lifetimes = item.generics.lifetimes().collect::<Vec<_>>();
    let ty_params = item.generics.type_params().collect::<Vec<_>>();
    let struct_ty = ty_for_foreign_derive(&item, &flags)?;

    let tokens = sql_types.map(|sql_type| {
        let lifetimes = &lifetimes;
        let ty_params = &ty_params;
        let tokens = quote!(
            impl<'expr, #(#lifetimes,)* #(#ty_params,)*> AsExpression<#sql_type>
                for &'expr #struct_ty
            {
                type Expression = Bound<#sql_type, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<'expr, #(#lifetimes,)* #(#ty_params,)*> AsExpression<Nullable<#sql_type>>
                for &'expr #struct_ty
            {
                type Expression = Bound<Nullable<#sql_type>, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<'expr2, 'expr, #(#lifetimes,)* #(#ty_params,)*> AsExpression<#sql_type>
                for &'expr2 &'expr #struct_ty
            {
                type Expression = Bound<#sql_type, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<'expr2, 'expr, #(#lifetimes,)* #(#ty_params,)*> AsExpression<Nullable<#sql_type>>
                for &'expr2 &'expr #struct_ty
            {
                type Expression = Bound<Nullable<#sql_type>, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<#(#lifetimes,)* #(#ty_params,)* __DB> diesel::serialize::ToSql<Nullable<#sql_type>, __DB>
                for #struct_ty
            where
                __DB: diesel::backend::Backend,
                Self: ToSql<#sql_type, __DB>,
            {
                fn to_sql<W: std::io::Write>(&self, out: &mut Output<W, __DB>) -> serialize::Result {
                    ToSql::<#sql_type, __DB>::to_sql(self, out)
                }
            }
        );
        if is_sized {
            quote!(
                #tokens

                impl#impl_generics AsExpression<#sql_type> for #struct_ty {
                    type Expression = Bound<#sql_type, Self>;

                    fn as_expression(self) -> Self::Expression {
                        Bound::new(self)
                    }
                }

                impl#impl_generics AsExpression<Nullable<#sql_type>> for #struct_ty {
                    type Expression = Bound<Nullable<#sql_type>, Self>;

                    fn as_expression(self) -> Self::Expression {
                        Bound::new(self)
                    }
                }
            )
        } else {
            tokens
        }
    });

    if any_sql_types {
        Ok(wrap_in_dummy_mod(quote! {
            use diesel::expression::AsExpression;
            use diesel::expression::bound::Bound;
            use diesel::sql_types::Nullable;
            use diesel::serialize::{self, ToSql, Output};

            #(#tokens)*
        }))
    } else {
        Ok(quote!())
    }
}
<commit_msg>Adding const-generics to AsExpression<commit_after>use proc_macro2;
use syn;

use meta::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagnostic> {
    let flags =
        MetaItem::with_name(&item.attrs, "diesel").unwrap_or_else(|| MetaItem::empty("diesel"));
    let is_sized = !flags.has_flag("not_sized");

    let sql_types = MetaItem::all_with_name(&item.attrs, "sql_type");
    let any_sql_types = !sql_types.is_empty();
    let sql_types = sql_types
        .into_iter()
        .filter_map(|attr| attr.ty_value().map_err(Diagnostic::emit).ok());

    let (impl_generics, ..) = item.generics.split_for_impl();
    let lifetimes = item.generics.lifetimes().collect::<Vec<_>>();
    let ty_params = item.generics.type_params().collect::<Vec<_>>();
    let const_params = item.generics.const_params().collect::<Vec<_>>();
    let struct_ty = ty_for_foreign_derive(&item, &flags)?;

    let tokens = sql_types.map(|sql_type| {
        let lifetimes = &lifetimes;
        let ty_params = &ty_params;
        let const_params = &const_params;
        let tokens = quote!(
            impl<'expr, #(#lifetimes,)* #(#ty_params,)* #(#const_params,)*> AsExpression<#sql_type>
                for &'expr #struct_ty
            {
                type Expression = Bound<#sql_type, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<'expr, #(#lifetimes,)* #(#ty_params,)* #(#const_params,)*> AsExpression<Nullable<#sql_type>>
                for &'expr #struct_ty
            {
                type Expression = Bound<Nullable<#sql_type>, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<'expr2, 'expr, #(#lifetimes,)* #(#ty_params,)* #(#const_params,)*> AsExpression<#sql_type>
                for &'expr2 &'expr #struct_ty
            {
                type Expression = Bound<#sql_type, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<'expr2, 'expr, #(#lifetimes,)* #(#ty_params,)* #(#const_params,)*> AsExpression<Nullable<#sql_type>>
                for &'expr2 &'expr #struct_ty
            {
                type Expression = Bound<Nullable<#sql_type>, Self>;

                fn as_expression(self) -> Self::Expression {
                    Bound::new(self)
                }
            }

            impl<#(#lifetimes,)* #(#ty_params,)* __DB,  #(#const_params,)*> diesel::serialize::ToSql<Nullable<#sql_type>, __DB>
                for #struct_ty
            where
                __DB: diesel::backend::Backend,
                Self: ToSql<#sql_type, __DB>,
            {
                fn to_sql<W: std::io::Write>(&self, out: &mut Output<W, __DB>) -> serialize::Result {
                    ToSql::<#sql_type, __DB>::to_sql(self, out)
                }
            }
        );
        if is_sized {
            quote!(
                #tokens

                impl#impl_generics AsExpression<#sql_type> for #struct_ty {
                    type Expression = Bound<#sql_type, Self>;

                    fn as_expression(self) -> Self::Expression {
                        Bound::new(self)
                    }
                }

                impl#impl_generics AsExpression<Nullable<#sql_type>> for #struct_ty {
                    type Expression = Bound<Nullable<#sql_type>, Self>;

                    fn as_expression(self) -> Self::Expression {
                        Bound::new(self)
                    }
                }
            )
        } else {
            tokens
        }
    });

    if any_sql_types {
        Ok(wrap_in_dummy_mod(quote! {
            use diesel::expression::AsExpression;
            use diesel::expression::bound::Bound;
            use diesel::sql_types::Nullable;
            use diesel::serialize::{self, ToSql, Output};

            #(#tokens)*
        }))
    } else {
        Ok(quote!())
    }
}
<|endoftext|>