<commit_before>//! An implementation of SipHash.

#![allow(deprecated)] // the types in this module are deprecated

use crate::cmp;
use crate::marker::PhantomData;
use crate::mem;
use crate::ptr;

/// An implementation of SipHash 1-3.
///
/// This is currently the default hashing function used by standard library
/// (e.g., `collections::HashMap` uses it by default).
///
/// See: <https://131002.net/siphash>
#[unstable(feature = "hashmap_internals", issue = "none")]
#[rustc_deprecated(
    since = "1.13.0",
    reason = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[derive(Debug, Clone, Default)]
#[doc(hidden)]
pub struct SipHasher13 {
    hasher: Hasher<Sip13Rounds>,
}

/// An implementation of SipHash 2-4.
///
/// See: <https://131002.net/siphash/>
#[unstable(feature = "hashmap_internals", issue = "none")]
#[rustc_deprecated(
    since = "1.13.0",
    reason = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[derive(Debug, Clone, Default)]
struct SipHasher24 {
    hasher: Hasher<Sip24Rounds>,
}

/// An implementation of SipHash 2-4.
///
/// See: <https://131002.net/siphash/>
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
/// hashing. This lets you key your hash tables from a strong RNG, such as
/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
///
/// Although the SipHash algorithm is considered to be generally strong,
/// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(
    since = "1.13.0",
    reason = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[derive(Debug, Clone, Default)]
pub struct SipHasher(SipHasher24);

#[derive(Debug)]
struct Hasher<S: Sip> {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    state: State,  // hash State
    tail: u64,     // unprocessed bytes le
    ntail: usize,  // how many bytes in tail are valid
    _marker: PhantomData<S>,
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct State {
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64,
    v2: u64,
    v1: u64,
    v3: u64,
}

macro_rules! compress {
    ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
        $v0 = $v0.wrapping_add($v1);
        $v1 = $v1.rotate_left(13);
        $v1 ^= $v0;
        $v0 = $v0.rotate_left(32);
        $v2 = $v2.wrapping_add($v3);
        $v3 = $v3.rotate_left(16);
        $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3);
        $v3 = $v3.rotate_left(21);
        $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1);
        $v1 = $v1.rotate_left(17);
        $v1 ^= $v2;
        $v2 = $v2.rotate_left(32);
    }};
}

/// Loads an integer of the desired type from a byte stream, in LE order. Uses
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load it from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
macro_rules! load_int_le {
    ($buf:expr, $i:expr, $int_ty:ident) => {{
        debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
        let mut data = 0 as $int_ty;
        ptr::copy_nonoverlapping(
            $buf.get_unchecked($i),
            &mut data as *mut _ as *mut u8,
            mem::size_of::<$int_ty>(),
        );
        data.to_le()
    }};
}

/// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the
/// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed
/// sizes and avoid calling `memcpy`, which is good for speed.
///
/// Unsafe because: unchecked indexing at start..start+len
#[inline]
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
    debug_assert!(len < 8);
    let mut i = 0; // current byte index (from LSB) in the output u64
    let mut out = 0;
    if i + 3 < len {
        // SAFETY: `i` cannot be greater than `len`, and the caller must guarantee
        // that the index start..start+len is in bounds.
        out = unsafe { load_int_le!(buf, start + i, u32) } as u64;
        i += 4;
    }
    if i + 1 < len {
        // SAFETY: same as above.
        out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << (i * 8);
        i += 2
    }
    if i < len {
        // SAFETY: same as above.
        out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
        i += 1;
    }
    debug_assert_eq!(i, len);
    out
}

impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher` that is keyed off the provided keys.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) })
    }
}

impl SipHasher13 {
    /// Creates a new `SipHasher13` with the two initial keys set to 0.
    #[inline]
    #[unstable(feature = "hashmap_internals", issue = "none")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new() -> SipHasher13 {
        SipHasher13::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher13` that is keyed off the provided keys.
    #[inline]
    #[unstable(feature = "hashmap_internals", issue = "none")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
        SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
    }
}

impl<S: Sip> Hasher<S> {
    #[inline]
    fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
        let mut state = Hasher {
            k0: key0,
            k1: key1,
            length: 0,
            state: State { v0: 0, v1: 0, v2: 0, v3: 0 },
            tail: 0,
            ntail: 0,
            _marker: PhantomData,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.state.v0 = self.k0 ^ 0x736f6d6570736575;
        self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.state.v2 = self.k0 ^ 0x6c7967656e657261;
        self.state.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl super::Hasher for SipHasher {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        self.0.hasher.write(msg)
    }

    #[inline]
    fn finish(&self) -> u64 {
        self.0.hasher.finish()
    }
}

#[unstable(feature = "hashmap_internals", issue = "none")]
impl super::Hasher for SipHasher13 {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        self.hasher.write(msg)
    }

    #[inline]
    fn finish(&self) -> u64 {
        self.hasher.finish()
    }
}

impl<S: Sip> super::Hasher for Hasher<S> {
    // Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
    // for this type. We could add them, copy the `short_write` implementation
    // in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
    // methods to `SipHasher`, `SipHasher13`, and `DefaultHasher`. This would
    // greatly speed up integer hashing by those hashers, at the cost of
    // slightly slowing down compile speeds on some benchmarks. See #69152 for
    // details.
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            // SAFETY: `cmp::min(length, needed)` is guaranteed to not be over `length`
            self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail);
            if length < needed {
                self.ntail += length;
                return;
            } else {
                self.state.v3 ^= self.tail;
                S::c_rounds(&mut self.state);
                self.state.v0 ^= self.tail;
                self.ntail = 0;
            }
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7; // len % 8

        let mut i = needed;
        while i < len - left {
            // SAFETY: because `len - left` is the biggest multiple of 8 under
            // `len`, and because `i` starts at `needed` where `len` is `length - needed`,
            // `i + 8` is guaranteed to be less than or equal to `length`.
            let mi = unsafe { load_int_le!(msg, i, u64) };

            self.state.v3 ^= mi;
            S::c_rounds(&mut self.state);
            self.state.v0 ^= mi;

            i += 8;
        }

        // SAFETY: `i` is now `needed + len.div_euclid(8) * 8`,
        // so `i + left` = `needed + len` = `length`, which is by
        // definition equal to `msg.len()`.
        self.tail = unsafe { u8to64_le(msg, i, left) };
        self.ntail = left;
    }

    #[inline]
    fn finish(&self) -> u64 {
        let mut state = self.state;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        state.v3 ^= b;
        S::c_rounds(&mut state);
        state.v0 ^= b;

        state.v2 ^= 0xff;
        S::d_rounds(&mut state);

        state.v0 ^ state.v1 ^ state.v2 ^ state.v3
    }
}

impl<S: Sip> Clone for Hasher<S> {
    #[inline]
    fn clone(&self) -> Hasher<S> {
        Hasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            state: self.state,
            tail: self.tail,
            ntail: self.ntail,
            _marker: self._marker,
        }
    }
}

impl<S: Sip> Default for Hasher<S> {
    /// Creates a `Hasher<S>` with the two initial keys set to 0.
    #[inline]
    fn default() -> Hasher<S> {
        Hasher::new_with_keys(0, 0)
    }
}

#[doc(hidden)]
trait Sip {
    fn c_rounds(_: &mut State);
    fn d_rounds(_: &mut State);
}

#[derive(Debug, Clone, Default)]
struct Sip13Rounds;

impl Sip for Sip13Rounds {
    #[inline]
    fn c_rounds(state: &mut State) {
        compress!(state);
    }

    #[inline]
    fn d_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
        compress!(state);
    }
}

#[derive(Debug, Clone, Default)]
struct Sip24Rounds;

impl Sip for Sip24Rounds {
    #[inline]
    fn c_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
    }

    #[inline]
    fn d_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
        compress!(state);
        compress!(state);
    }
}
<commit_msg>fix aliasing issues in SipHasher<commit_after>//! An implementation of SipHash.

#![allow(deprecated)] // the types in this module are deprecated

use crate::cmp;
use crate::marker::PhantomData;
use crate::mem;
use crate::ptr;

/// An implementation of SipHash 1-3.
///
/// This is currently the default hashing function used by standard library
/// (e.g., `collections::HashMap` uses it by default).
///
/// See: <https://131002.net/siphash>
#[unstable(feature = "hashmap_internals", issue = "none")]
#[rustc_deprecated(
    since = "1.13.0",
    reason = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[derive(Debug, Clone, Default)]
#[doc(hidden)]
pub struct SipHasher13 {
    hasher: Hasher<Sip13Rounds>,
}

/// An implementation of SipHash 2-4.
///
/// See: <https://131002.net/siphash/>
#[unstable(feature = "hashmap_internals", issue = "none")]
#[rustc_deprecated(
    since = "1.13.0",
    reason = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[derive(Debug, Clone, Default)]
struct SipHasher24 {
    hasher: Hasher<Sip24Rounds>,
}

/// An implementation of SipHash 2-4.
///
/// See: <https://131002.net/siphash/>
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
/// hashing. This lets you key your hash tables from a strong RNG, such as
/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
///
/// Although the SipHash algorithm is considered to be generally strong,
/// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(
    since = "1.13.0",
    reason = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[derive(Debug, Clone, Default)]
pub struct SipHasher(SipHasher24);

#[derive(Debug)]
struct Hasher<S: Sip> {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    state: State,  // hash State
    tail: u64,     // unprocessed bytes le
    ntail: usize,  // how many bytes in tail are valid
    _marker: PhantomData<S>,
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct State {
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64,
    v2: u64,
    v1: u64,
    v3: u64,
}

macro_rules! compress {
    ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
        $v0 = $v0.wrapping_add($v1);
        $v1 = $v1.rotate_left(13);
        $v1 ^= $v0;
        $v0 = $v0.rotate_left(32);
        $v2 = $v2.wrapping_add($v3);
        $v3 = $v3.rotate_left(16);
        $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3);
        $v3 = $v3.rotate_left(21);
        $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1);
        $v1 = $v1.rotate_left(17);
        $v1 ^= $v2;
        $v2 = $v2.rotate_left(32);
    }};
}

/// Loads an integer of the desired type from a byte stream, in LE order. Uses
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load it from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
macro_rules! load_int_le {
    ($buf:expr, $i:expr, $int_ty:ident) => {{
        debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
        let mut data = 0 as $int_ty;
        ptr::copy_nonoverlapping(
            $buf.as_ptr().add($i),
            &mut data as *mut _ as *mut u8,
            mem::size_of::<$int_ty>(),
        );
        data.to_le()
    }};
}

/// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the
/// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed
/// sizes and avoid calling `memcpy`, which is good for speed.
///
/// Unsafe because: unchecked indexing at start..start+len
#[inline]
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
    debug_assert!(len < 8);
    let mut i = 0; // current byte index (from LSB) in the output u64
    let mut out = 0;
    if i + 3 < len {
        // SAFETY: `i` cannot be greater than `len`, and the caller must guarantee
        // that the index start..start+len is in bounds.
        out = unsafe { load_int_le!(buf, start + i, u32) } as u64;
        i += 4;
    }
    if i + 1 < len {
        // SAFETY: same as above.
        out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << (i * 8);
        i += 2
    }
    if i < len {
        // SAFETY: same as above.
        out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
        i += 1;
    }
    debug_assert_eq!(i, len);
    out
}

impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher` that is keyed off the provided keys.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) })
    }
}

impl SipHasher13 {
    /// Creates a new `SipHasher13` with the two initial keys set to 0.
    #[inline]
    #[unstable(feature = "hashmap_internals", issue = "none")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new() -> SipHasher13 {
        SipHasher13::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher13` that is keyed off the provided keys.
    #[inline]
    #[unstable(feature = "hashmap_internals", issue = "none")]
    #[rustc_deprecated(
        since = "1.13.0",
        reason = "use `std::collections::hash_map::DefaultHasher` instead"
    )]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
        SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
    }
}

impl<S: Sip> Hasher<S> {
    #[inline]
    fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
        let mut state = Hasher {
            k0: key0,
            k1: key1,
            length: 0,
            state: State { v0: 0, v1: 0, v2: 0, v3: 0 },
            tail: 0,
            ntail: 0,
            _marker: PhantomData,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.state.v0 = self.k0 ^ 0x736f6d6570736575;
        self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.state.v2 = self.k0 ^ 0x6c7967656e657261;
        self.state.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl super::Hasher for SipHasher {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        self.0.hasher.write(msg)
    }

    #[inline]
    fn finish(&self) -> u64 {
        self.0.hasher.finish()
    }
}

#[unstable(feature = "hashmap_internals", issue = "none")]
impl super::Hasher for SipHasher13 {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        self.hasher.write(msg)
    }

    #[inline]
    fn finish(&self) -> u64 {
        self.hasher.finish()
    }
}

impl<S: Sip> super::Hasher for Hasher<S> {
    // Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
    // for this type. We could add them, copy the `short_write` implementation
    // in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
    // methods to `SipHasher`, `SipHasher13`, and `DefaultHasher`. This would
    // greatly speed up integer hashing by those hashers, at the cost of
    // slightly slowing down compile speeds on some benchmarks. See #69152 for
    // details.
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            // SAFETY: `cmp::min(length, needed)` is guaranteed to not be over `length`
            self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail);
            if length < needed {
                self.ntail += length;
                return;
            } else {
                self.state.v3 ^= self.tail;
                S::c_rounds(&mut self.state);
                self.state.v0 ^= self.tail;
                self.ntail = 0;
            }
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7; // len % 8

        let mut i = needed;
        while i < len - left {
            // SAFETY: because `len - left` is the biggest multiple of 8 under
            // `len`, and because `i` starts at `needed` where `len` is `length - needed`,
            // `i + 8` is guaranteed to be less than or equal to `length`.
            let mi = unsafe { load_int_le!(msg, i, u64) };

            self.state.v3 ^= mi;
            S::c_rounds(&mut self.state);
            self.state.v0 ^= mi;

            i += 8;
        }

        // SAFETY: `i` is now `needed + len.div_euclid(8) * 8`,
        // so `i + left` = `needed + len` = `length`, which is by
        // definition equal to `msg.len()`.
        self.tail = unsafe { u8to64_le(msg, i, left) };
        self.ntail = left;
    }

    #[inline]
    fn finish(&self) -> u64 {
        let mut state = self.state;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        state.v3 ^= b;
        S::c_rounds(&mut state);
        state.v0 ^= b;

        state.v2 ^= 0xff;
        S::d_rounds(&mut state);

        state.v0 ^ state.v1 ^ state.v2 ^ state.v3
    }
}

impl<S: Sip> Clone for Hasher<S> {
    #[inline]
    fn clone(&self) -> Hasher<S> {
        Hasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            state: self.state,
            tail: self.tail,
            ntail: self.ntail,
            _marker: self._marker,
        }
    }
}

impl<S: Sip> Default for Hasher<S> {
    /// Creates a `Hasher<S>` with the two initial keys set to 0.
    #[inline]
    fn default() -> Hasher<S> {
        Hasher::new_with_keys(0, 0)
    }
}

#[doc(hidden)]
trait Sip {
    fn c_rounds(_: &mut State);
    fn d_rounds(_: &mut State);
}

#[derive(Debug, Clone, Default)]
struct Sip13Rounds;

impl Sip for Sip13Rounds {
    #[inline]
    fn c_rounds(state: &mut State) {
        compress!(state);
    }

    #[inline]
    fn d_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
        compress!(state);
    }
}

#[derive(Debug, Clone, Default)]
struct Sip24Rounds;

impl Sip for Sip24Rounds {
    #[inline]
    fn c_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
    }

    #[inline]
    fn d_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
        compress!(state);
        compress!(state);
    }
}
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::env;
use std::fs::create_dir_all;

#[derive(Debug)]
pub struct Movie {
    pub title: String,
    pub year: String,
}

pub fn db_exists() -> bool {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");
    path_buf.push("database");
    path_buf.set_extension("db");
    path_buf.as_path().exists()
}

fn get_connection() -> Connection {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");
    path_buf.push("database");
    path_buf.set_extension("db");

    let conn = Connection::open(path_buf).unwrap();
    conn
}

pub fn create_database() {

    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");

    // creates path if not existing
    create_dir_all(&path_buf);

    path_buf.push("database");
    path_buf.set_extension("db");

    let conn = Connection::open(path_buf).unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS movies (
                  id              INTEGER PRIMARY KEY,
                  title            TEXT NOT NULL,
                  year            TEXT NOT NULL,
                  genre           TEXT
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS actors (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS directors (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS rankings (
                  id              INTEGER PRIMARY KEY,
                  movie_id        INTEGER,
                  score           TEXT NOT NULL,
                  number          TEXT NOT NULL,
                  FOREIGN KEY(movie_id) REFERENCES movies(id)
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS crew_a (
                  actor_id        INTEGER,
                  movie_id        INTEGER,
                  FOREIGN KEY(movie_id) REFERENCES movies(id),
                  FOREIGN KEY(actor_id) REFERENCES actors(id)
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS crew_d (
                  director_id        INTEGER,
                  movie_id        INTEGER,
                  FOREIGN KEY(movie_id) REFERENCES movies(id),
                  FOREIGN KEY(director_id) REFERENCES directors(id)
                  )",
                 &[])
        .unwrap();
}

pub fn import_movie(title: &str, year: &str) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO movies (title, year) VALUES ('{}', '{}')",
                          title,
                          year),
                 &[])
        .unwrap();
}

pub fn add_genres(title: &str, year: &str, genre: &str) {
    let conn = get_connection();

    conn.execute(&format!("UPDATE movies SET genre = '{}' WHERE title = '{}' AND year = '{}'",
                          genre,
                          title,
                          year),
                 &[])
        .unwrap();
}

pub fn add_rating(title: &str, year: &str, rank: &str, votes: &str) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO rankings (movie_id, score, number) VALUES ((SELECT id \
                           FROM movies WHERE title = '{}' AND year = '{}'), '{}', '{}')",
                          title,
                          year,
                          rank,
                          votes),
                 &[])
        .unwrap();
}

pub fn add_actor(name: &str, movies: Vec<Movie>) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO actors (name) VALUES ('{}')", &name),
                 &[])
        .unwrap();

    for m in movies {
        conn.execute(&format!("INSERT INTO crew_a (actor_id, movie_id) VALUES ((SELECT id FROM \
                               actors WHERE name = '{}'), (SELECT id FROM movies WHERE title = \
                               '{}' AND year = '{}'))",
                              name,
                              m.title,
                              m.year),
                     &[])
            .unwrap();
    }
}

pub fn add_director(name: &str, movies: Vec<Movie>) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO directors (name) VALUES ('{}')", &name),
                 &[])
        .unwrap();

    for m in movies {
        conn.execute(&format!("INSERT INTO crew_d (director_id, movie_id) VALUES ((SELECT id \
                               FROM directors WHERE name = '{}'), (SELECT id FROM movies WHERE \
                               title = '{}' AND year = '{}'))",
                              name,
                              m.title,
                              m.year),
                     &[])
            .unwrap();
    }
}
<commit_msg>Add comments<commit_after>use rusqlite::Connection;
use std::env;
use std::fs::create_dir_all;

#[derive(Debug)]
// A struct to represent a movie to be attached to actors or directors
pub struct Movie {
    pub title: String,
    pub year: String,
}

// Checks if a database already exists
pub fn db_exists() -> bool {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");
    path_buf.push("database");
    path_buf.set_extension("db");
    path_buf.as_path().exists()
}

fn get_connection() -> Connection {
    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");
    path_buf.push("database");
    path_buf.set_extension("db");

    let conn = Connection::open(path_buf).unwrap();
    conn
}

// Creates a database with movies and related information for movie suggestions
// Movies: movie titles with associated release date and genre
// Actors: names of all actors
// Rankings: associates movie ID with IMDb ratings and number of ratings
// Crew (actors and directors): associates actors/directors with their movies
pub fn create_database() {

    let tmp = env::home_dir();
    let mut path_buf = tmp.unwrap();
    path_buf.push("Film-O-Mat");

    // creates path if not existing
    create_dir_all(&path_buf);

    path_buf.push("database");
    path_buf.set_extension("db");

    let conn = Connection::open(path_buf).unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS movies (
                  id              INTEGER PRIMARY KEY,
                  title            TEXT NOT NULL,
                  year            TEXT NOT NULL,
                  genre           TEXT
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS actors (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS directors (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS rankings (
                  id              INTEGER PRIMARY KEY,
                  movie_id        INTEGER,
                  score           TEXT NOT NULL,
                  number          TEXT NOT NULL,
                  FOREIGN KEY(movie_id) REFERENCES movies(id)
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS crew_a (
                  actor_id        INTEGER,
                  movie_id        INTEGER,
                  FOREIGN KEY(movie_id) REFERENCES movies(id),
                  FOREIGN KEY(actor_id) REFERENCES actors(id)
                  )",
                 &[])
        .unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS crew_d (
                  director_id        INTEGER,
                  movie_id        INTEGER,
                  FOREIGN KEY(movie_id) REFERENCES movies(id),
                  FOREIGN KEY(director_id) REFERENCES directors(id)
                  )",
                 &[])
        .unwrap();
}

// List of movies with their year of release
pub fn import_movie(title: &str, year: &str) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO movies (title, year) VALUES ('{}', '{}')",
                          title,
                          year),
                 &[])
        .unwrap();
}

// Genre information is added to the movie list
pub fn add_genres(title: &str, year: &str, genre: &str) {
    let conn = get_connection();

    conn.execute(&format!("UPDATE movies SET genre = '{}' WHERE title = '{}' AND year = '{}'",
                          genre,
                          title,
                          year),
                 &[])
        .unwrap();
}

// List of ratings with information of user ratings
pub fn add_rating(title: &str, year: &str, rank: &str, votes: &str) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO rankings (movie_id, score, number) VALUES ((SELECT id \
                           FROM movies WHERE title = '{}' AND year = '{}'), '{}', '{}')",
                          title,
                          year,
                          rank,
                          votes),
                 &[])
        .unwrap();
}

// List of all actors, independent of their movies
// Connection between actors and their movies outsourced to separate list
pub fn add_actor(name: &str, movies: Vec<Movie>) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO actors (name) VALUES ('{}')", &name),
                 &[])
        .unwrap();

    for m in movies {
        conn.execute(&format!("INSERT INTO crew_a (actor_id, movie_id) VALUES ((SELECT id FROM \
                               actors WHERE name = '{}'), (SELECT id FROM movies WHERE title = \
                               '{}' AND year = '{}'))",
                              name,
                              m.title,
                              m.year),
                     &[])
            .unwrap();
    }
}

// List of all directors, independent of their movies
// Connection between directors and their movies outsourced to separate list
pub fn add_director(name: &str, movies: Vec<Movie>) {
    let conn = get_connection();

    conn.execute(&format!("INSERT INTO directors (name) VALUES ('{}')", &name),
                 &[])
        .unwrap();

    for m in movies {
        conn.execute(&format!("INSERT INTO crew_d (director_id, movie_id) VALUES ((SELECT id \
                               FROM directors WHERE name = '{}'), (SELECT id FROM movies WHERE \
                               title = '{}' AND year = '{}'))",
                              name,
                              m.title,
                              m.year),
                     &[])
            .unwrap();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
extern crate glob;
use self::glob::glob;

extern crate toml;
mod basics;
mod tiff;
mod mrw;

pub trait Decoder {
  fn identify(&self) -> Result<&Camera, String>;
  fn image(&self) -> Image;
}

pub struct Image {
  pub width: u32,
  pub height: u32,
  pub wb_coeffs: [f32;4],
  pub data: Box<[u16]>,
}

#[derive(Debug)]
pub struct Camera {
  pub make: String,
  pub model: String,
  pub canonical_make: String,
  pub canonical_model: String,
}

impl Camera {
  pub fn from_toml(text: &str) -> Camera {
    let camvalue = toml::Parser::new(text).parse().unwrap();
    let cameradata = camvalue.get("camera").unwrap().as_table().unwrap();
    let make = cameradata.get("make").unwrap().as_str().unwrap().to_string();
    let model = cameradata.get("model").unwrap().as_str().unwrap().to_string();
    Camera{make: make.clone(), model: model.clone(), canonical_make: make.clone(), canonical_model: model.clone()}
  }
}

#[derive(Debug)]
pub struct RawLoader {
  pub cameras: HashMap<(String,String),Camera>,
}

impl RawLoader {
  pub fn new(path: &str) -> RawLoader {
    let mut map = HashMap::new();

    for entry in glob(&(path.to_string()+"/**/*.toml")).expect("Failed to read glob pattern") {
      match entry {
        Ok(path) => {
          let mut f = File::open(path).unwrap();
          let mut toml = String::new();
          f.read_to_string(&mut toml).unwrap();
          let cmd = Camera::from_toml(&toml);
          map.insert((cmd.make.clone(),cmd.model.clone()), cmd);
        }
        Err(err) => panic!(err),
      }
    }

    RawLoader{
      cameras: map,
    }
  }

  pub fn get_decoder<'b>(&'b self, buffer: &'b [u8]) -> Result<Box<Decoder+'b>, String> {
    if mrw::is_mrw(buffer) {
      let dec = Box::new(mrw::MrwDecoder::new(buffer, &self));
      return Ok(dec as Box<Decoder>);
    }
    Err("Couldn't find a decoder!".to_string())
  }

  pub fn check_supported<'a>(&'a self, make: &'a str, model: &'a str) -> Result<&Camera, String> {
    match self.cameras.get(&(make.to_string(),model.to_string())) {
      Some(cam) => Ok(cam),
      None => Err(format!("Couldn't find camera \"{}\" \"{}\"", make, model)),
    }
  }
}
<commit_msg>Remove last unwrap()s in the toml loading code<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
extern crate glob;
use self::glob::glob;

extern crate toml;
mod basics;
mod tiff;
mod mrw;

pub trait Decoder {
  fn identify(&self) -> Result<&Camera, String>;
  fn image(&self) -> Image;
}

pub struct Image {
  pub width: u32,
  pub height: u32,
  pub wb_coeffs: [f32;4],
  pub data: Box<[u16]>,
}

#[derive(Debug)]
pub struct Camera {
  pub make: String,
  pub model: String,
  pub canonical_make: String,
  pub canonical_model: String,
}

impl Camera {
  pub fn from_toml(text: &str) -> Result<Camera, String> {
    let camvalue = match toml::Parser::new(text).parse() {
      Some(val) => val,
      None => return Err("parse failed".to_string())
    };
    let cameradata = match camvalue.get("camera") {
      Some(c) => match c.as_table() {
        Some(tbl) => tbl,
        None => return Err("parsing [camera] failed".to_string())
      },
      None => return Err("parsing [camera] failed".to_string()),
    };

    let make = match cameradata.get("make") {
      Some(m) => match m.as_str() {
        Some(ms) => ms.to_string(),
        None => return Err("parsing [camera]->make failed".to_string()),
      },
      None => return Err("parsing [camera]->make failed".to_string()),
    };
    let model = match cameradata.get("model") {
      Some(m) => match m.as_str() {
        Some(ms) => ms.to_string(),
        None => return Err("parsing [camera]->model failed".to_string()),
      },
      None => return Err("parsing [camera]->model failed".to_string()),
    };
    Ok(Camera{
      make: make.clone(),
      model: model.clone(),
      canonical_make: make.clone(),
      canonical_model: model.clone()
    })
  }
}

#[derive(Debug)]
pub struct RawLoader {
  pub cameras: HashMap<(String,String),Camera>,
}

impl RawLoader {
  pub fn new(path: &str) -> RawLoader {
    let mut map = HashMap::new();

    for entry in glob(&(path.to_string()+"/**/*.toml")).expect("Failed to read glob pattern") {
      match entry {
        Ok(path) => {
          let mut f = match File::open(path) {
            Ok(val) => val,
            Err(_) => continue,
          };
          let mut toml = String::new();
          if f.read_to_string(&mut toml).is_err() {
            continue
          }
          let cmd = match Camera::from_toml(&toml) {
            Ok(val) => val,
            Err(_) => continue,
          };
          map.insert((cmd.make.clone(),cmd.model.clone()), cmd);
        }
        Err(err) => panic!(err),
      }
    }

    RawLoader{
      cameras: map,
    }
  }

  pub fn get_decoder<'b>(&'b self, buffer: &'b [u8]) -> Result<Box<Decoder+'b>, String> {
    if mrw::is_mrw(buffer) {
      let dec = Box::new(mrw::MrwDecoder::new(buffer, &self));
      return Ok(dec as Box<Decoder>);
    }
    Err("Couldn't find a decoder!".to_string())
  }

  pub fn check_supported<'a>(&'a self, make: &'a str, model: &'a str) -> Result<&Camera, String> {
    match self.cameras.get(&(make.to_string(),model.to_string())) {
      Some(cam) => Ok(cam),
      None => Err(format!("Couldn't find camera \"{}\" \"{}\"", make, model)),
    }
  }
}
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub fn disassemble(raw: &[u8]) -> String {
    let mut result = String::new();

    let mut i: usize = 0;
    while i < raw.len() {
        let opcode = OpCode::from_raw_byte(raw[i]);
        let val = match opcode.mode {
            AddressingMode::Implied |
            AddressingMode::Accumulator => String::from(""),
            AddressingMode::Immediate => format!(" #${:X}", raw[i + 0x01]),
            AddressingMode::Indirect => {
                format!(" (${:X})", LittleEndian::read_u16(&raw[i + 0x01..]))
            }
            AddressingMode::Relative => format!(" #${:X}", raw[i + 0x01]),
            AddressingMode::Absolute => format!(" ${:X}", LittleEndian::read_u16(&raw[i + 0x01..])),
            AddressingMode::ZeroPage => format!(" ${:X}", raw[i + 0x01]),
            AddressingMode::ZeroPageX => format!(" ${:X},X", raw[i + 0x01]),
            AddressingMode::ZeroPageY => format!(" ${:X},Y", raw[i + 0x01]),
            _ => String::from(""),
        };
        let opcode_text = format!("{}{}\n", opcode.mnemonic, val);
        result.push_str(&opcode_text);
        i += opcode.length as usize;
    }

    result
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = disassemble(&code);

        assert_eq!(clean_asm("

            LDA #$20
            STA $4400

        "),
                   clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = disassemble(&code);

        assert_eq!(clean_asm("

            JMP ($4400)

        "),
                   clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let code: Vec<u8> = vec![0xD0, 0xFF];
        let asm = disassemble(&code);

        assert_eq!(clean_asm("

            BNE #$FF

        "),
                   clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = disassemble(&code);

        assert_eq!(clean_asm("

            LDA $35

        "),
                   clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = disassemble(&code);

        assert_eq!(clean_asm("

            STA $44,X
            STX $FE,Y

        "),
                   clean_asm(asm));
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line from some text input, with
    /// all leading and trailing whitespace removed.
    fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}
<commit_msg>Add support for all addressing modes in Disassembler<commit_after>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler;

impl Disassembler {
    pub fn disassemble(raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);
            let val = match opcode.mode {
                AddressingMode::Implied |
                AddressingMode::Accumulator => String::from(""),
                AddressingMode::Immediate => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::Indirect => {
                    format!(" (${:04X})", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::Relative => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPage => format!(" ${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPageX => format!(" ${:02X},X", raw[i + 0x01]),
                AddressingMode::ZeroPageY => format!(" ${:02X},Y", raw[i + 0x01]),
                AddressingMode::Absolute => {
                    format!(" ${:04X}", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteX => {
                    format!(" ${:04X},X", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteY => {
                    format!(" ${:04X},Y", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::IndirectX => format!(" (${:02X},X)", raw[i + 0x01]),
                AddressingMode::IndirectY => format!(" (${:02X}),Y", raw[i + 0x01]),
            };
            let opcode_text = format!("{}{}\n", opcode.mnemonic, val);
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line from some text input, with
    /// all leading and trailing whitespace removed.
    fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            LDA #$20
            STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let code: Vec<u8> = vec![0xD0, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            BNE #$FF

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA $44,X
            STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA $4400,X
            STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA ($44,X)
            STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = Disassembler::disassemble(&code);

        print!("{}", asm);
    }
}
<|endoftext|>


<commit_before>use std::env::var;
///
/// Tells Cargo to link the correct libraries
///

fn main() {
    let target = var("TARGET").ok().expect("No TARGET environment variable");

    if target.contains("-apple-") {
        println!("cargo:rustc-link-search=framework=SDK/Libraries/Mac/");
        println!("cargo:rustc-link-lib=framework=XPLM");
        println!("cargo:rustc-link-lib=framework=XPWidgets");
    }
    else if target.contains("-linux-") {
        // Do nothing for Linux
    }
    else {
        panic!("Unknown operating system (target = {}) is not supported", target);
    }
}
<commit_msg>Made link script work on Windows<commit_after>use std::env::var;
///
/// Tells Cargo to link the correct libraries
///

fn main() {
    let target = var("TARGET").ok().expect("No TARGET environment variable");

    if target.contains("-apple-") {
        println!("cargo:rustc-link-search=framework=SDK/Libraries/Mac/");
        println!("cargo:rustc-link-lib=framework=XPLM");
        println!("cargo:rustc-link-lib=framework=XPWidgets");
    }
    else if target.contains("-linux-") {
        // Do nothing for Linux
    }
    else if target.contains("-windows-") {
        println!("cargo:rustc-link-search=SDK/Libraries/Win/");
		if target.contains("x86_64") {
			println!("cargo:rustc-link-lib=XPLM_64");
			println!("cargo:rustc-link-lib=XPWidgets_64");
		}
		else {
			println!("cargo:rustc-link-lib=XPLM");
			println!("cargo:rustc-link-lib=XPWidgets");
		}
    }
    else {
        panic!("Unknown operating system (target = {}) is not supported", target);
    }
}
<|endoftext|>


<commit_before>
use syn::*;
use quote::Tokens;
use methodinfo::RustArg;
use tyhandlers;
use utils;

/// Defines return handler for handling various different return type schemes.
pub trait ReturnHandler : ::std::fmt::Debug {

    /// The return type of the original Rust method.
    fn rust_ty( &self ) -> Type;

    /// The return type for COM implementation.
    fn com_ty( &self ) -> Type
    {
        tyhandlers::get_ty_handler( &self.rust_ty() ).com_ty()
    }

    /// Gets the return statement for converting the COM result into Rust
    /// return.
    fn com_to_rust_return( &self, _result : &Ident ) -> Tokens { quote!() }

    /// Gets the return statement for converting the Rust result into COM
    /// outputs.
    fn rust_to_com_return( &self, _result : &Ident ) -> Tokens { quote!() }

    /// Gets the COM out arguments that result from the Rust return type.
    fn com_out_args( &self ) -> Vec<RustArg> { vec![] }
}

/// Void return type.
#[derive(Debug)]
struct VoidHandler;
impl ReturnHandler for VoidHandler {
    fn rust_ty( &self ) -> Type { utils::unit_ty() }
}

/// Simple return type with the return value as the immediate value.
#[derive(Debug)]
struct ReturnOnlyHandler( Type );
impl ReturnHandler for ReturnOnlyHandler {

    fn rust_ty( &self ) -> Type { self.0.clone() }

    fn com_to_rust_return( &self, result : &Ident ) -> Tokens {
        quote!( #result.into() )
    }

    fn rust_to_com_return( &self, result : &Ident ) -> Tokens {
        quote!( #result.into() )
    }

    fn com_out_args( &self ) -> Vec<RustArg> { vec![] }
}

/// Result type that supports error info for the `Err` value. Converted to
/// `[retval]` on success or `HRESULT` + `IErrorInfo` on error.
#[derive(Debug)]
struct ErrorResultHandler { retval_ty: Type, return_ty: Type }
impl ReturnHandler for ErrorResultHandler {

    fn rust_ty( &self ) -> Type { self.return_ty.clone() }
    fn com_ty( &self ) -> Type { parse_quote!( ::intercom::HRESULT ) }

    fn com_to_rust_return( &self, result : &Ident ) -> Tokens {

        // Return statement checks for S_OK (should be is_success) HRESULT and
        // yields either Ok or Err Result based on that.
        let ok_values = get_ok_values( self.com_out_args() );
        let ok_tokens = if ok_values.len() != 1 {
                quote!( ( #( #ok_values ),* ) )
            } else {
                quote!( #( #ok_values )* )
            };
        quote!(
            if #result == ::intercom::S_OK {
                Ok( #ok_tokens )
            } else {
                Err( ::intercom::get_last_error( #result ) )
            }
        )
    }

    fn rust_to_com_return( &self, result : &Ident ) -> Tokens {

        // Get the OK idents. We'll use v0, v1, v2, ... depending on the amount
        // of patterns we need for possible tuples.
        let ok_idents = self.com_out_args()
                    .iter()
                    .enumerate()
                    .map( |(idx, _)| Ident::from( format!( "v{}", idx + 1 ) ) )
                    .collect::<Vec<_>>();

        // Generate the pattern for the Ok(..).
        // Tuples get (v0, v1, v2, ..) pattern while everything else is
        // represented with just Ok( v0 ) as there's just one parameter.
        let ok_pattern = {
            // quote! takes ownership of tokens if we allow so let's give them
            // by reference here.
            let rok_idents = &ok_idents;
            match self.retval_ty {
                Type::Tuple( _ ) => quote!( ( #( #rok_idents ),* ) ),

                // Non-tuples should have only one ident. Concatenate the vector.
                _ => quote!( #( #rok_idents )* ),
            }
        };

        let ( ok_writes, err_writes ) = write_out_values(
            &ok_idents,
            self.com_out_args() );
        quote!(
            match #result {
                Ok( #ok_pattern ) => { #( #ok_writes );*; ::intercom::S_OK },
                Err( e ) => {
                    #( #err_writes );*;
                    ::intercom::return_hresult( e )
                },
            }
        )
    }

    fn com_out_args( &self ) -> Vec<RustArg> {
        get_out_args_for_result( &self.retval_ty )
    }
}

fn get_out_args_for_result( retval_ty : &Type ) -> Vec<RustArg> {

    match *retval_ty {

        // Tuples map to multiple out args, no [retval].
        Type::Tuple( ref t ) =>
            t.elems.iter()
                .enumerate()
                .map( |( idx, ty )| RustArg::new(
                                    Ident::from( format!( "__out{}", idx + 1) ),
                                    ty.clone() ) )
                .collect::<Vec<_>>(),
        _ => vec![ RustArg::new( Ident::from( "__out" ), retval_ty.clone() ) ],
    }
}

fn write_out_values(
    idents : &[Ident],
    out_args : Vec<RustArg>,
) -> ( Vec<Tokens>, Vec<Tokens> )
{
    let mut ok_tokens = vec![];
    let mut err_tokens = vec![];
    for ( ident, out_arg ) in idents.iter().zip( out_args ) {

        let arg_name = out_arg.name;
        let ok_value = out_arg.handler.rust_to_com( *ident );
        let err_value = out_arg.handler.default_value();
        ok_tokens.push( quote!( *#arg_name = #ok_value ) );
        err_tokens.push( quote!( *#arg_name = #err_value ) );
    }

    ( ok_tokens, err_tokens )
}

fn get_ok_values(
    out_args : Vec<RustArg>
) -> Vec<Tokens>
{
    let mut tokens = vec![];
    for out_arg in out_args {

        let arg_value = out_arg.handler.rust_to_com( &out_arg.name );
        tokens.push( quote!( #arg_value ) );
    }
    tokens
}

/// Resolves the correct return handler to use.
pub fn get_return_handler(
    retval_ty : &Option< Type >,
    return_ty : &Option< Type >
) -> Result< Box<ReturnHandler>, () >
{
    Ok( match ( retval_ty, return_ty ) {
        ( &None, &None ) => Box::new( VoidHandler ),
        ( &None, &Some( ref ty ) )
            => Box::new( ReturnOnlyHandler( ty.clone() ) ),
        ( &Some( ref rv ), &Some( ref rt ) )
            => Box::new( ErrorResultHandler {
                retval_ty: rv.clone(),
                return_ty: rt.clone(),
            } ),

        // Unsupported return scheme. Note we are using Result::Err instead of
        // Option::None here because having no return handler is unsupported
        // error case.
        _ => return Err( () ),
    } )
}
<commit_msg>Fix return value convert direction<commit_after>
use syn::*;
use quote::Tokens;
use methodinfo::RustArg;
use tyhandlers;
use utils;

/// Defines return handler for handling various different return type schemes.
pub trait ReturnHandler : ::std::fmt::Debug {

    /// The return type of the original Rust method.
    fn rust_ty( &self ) -> Type;

    /// The return type for COM implementation.
    fn com_ty( &self ) -> Type
    {
        tyhandlers::get_ty_handler( &self.rust_ty() ).com_ty()
    }

    /// Gets the return statement for converting the COM result into Rust
    /// return.
    fn com_to_rust_return( &self, _result : &Ident ) -> Tokens { quote!() }

    /// Gets the return statement for converting the Rust result into COM
    /// outputs.
    fn rust_to_com_return( &self, _result : &Ident ) -> Tokens { quote!() }

    /// Gets the COM out arguments that result from the Rust return type.
    fn com_out_args( &self ) -> Vec<RustArg> { vec![] }
}

/// Void return type.
#[derive(Debug)]
struct VoidHandler;
impl ReturnHandler for VoidHandler {
    fn rust_ty( &self ) -> Type { utils::unit_ty() }
}

/// Simple return type with the return value as the immediate value.
#[derive(Debug)]
struct ReturnOnlyHandler( Type );
impl ReturnHandler for ReturnOnlyHandler {

    fn rust_ty( &self ) -> Type { self.0.clone() }

    fn com_to_rust_return( &self, result : &Ident ) -> Tokens {
        quote!( #result.into() )
    }

    fn rust_to_com_return( &self, result : &Ident ) -> Tokens {
        quote!( #result.into() )
    }

    fn com_out_args( &self ) -> Vec<RustArg> { vec![] }
}

/// Result type that supports error info for the `Err` value. Converted to
/// `[retval]` on success or `HRESULT` + `IErrorInfo` on error.
#[derive(Debug)]
struct ErrorResultHandler { retval_ty: Type, return_ty: Type }
impl ReturnHandler for ErrorResultHandler {

    fn rust_ty( &self ) -> Type { self.return_ty.clone() }
    fn com_ty( &self ) -> Type { parse_quote!( ::intercom::HRESULT ) }

    fn com_to_rust_return( &self, result : &Ident ) -> Tokens {

        // Quote the OK values.
        // If there is only one, it should be a raw value;
        // If there are multiple value quote them as a tuple.
        let ok_values = get_rust_ok_values( self.com_out_args() );
        let ok_tokens = if ok_values.len() != 1 {
                quote!( ( #( #ok_values ),* ) )
            } else {
                quote!( #( #ok_values )* )
            };

        // Return statement checks for S_OK (should be is_success) HRESULT and
        // yields either Ok or Err Result based on that.
        quote!(
            if #result == ::intercom::S_OK {
                Ok( #ok_tokens )
            } else {
                Err( ::intercom::get_last_error( #result ) )
            }
        )
    }

    fn rust_to_com_return( &self, result : &Ident ) -> Tokens {

        // Get the OK idents. We'll use v0, v1, v2, ... depending on the amount
        // of patterns we need for possible tuples.
        let ok_idents = self.com_out_args()
                    .iter()
                    .enumerate()
                    .map( |(idx, _)| Ident::from( format!( "v{}", idx + 1 ) ) )
                    .collect::<Vec<_>>();

        // Generate the pattern for the Ok(..).
        // Tuples get (v0, v1, v2, ..) pattern while everything else is
        // represented with just Ok( v0 ) as there's just one parameter.
        let ok_pattern = {
            // quote! takes ownership of tokens if we allow so let's give them
            // by reference here.
            let rok_idents = &ok_idents;
            match self.retval_ty {
                Type::Tuple( _ ) => quote!( ( #( #rok_idents ),* ) ),

                // Non-tuples should have only one ident. Concatenate the vector.
                _ => quote!( #( #rok_idents )* ),
            }
        };

        let ( ok_writes, err_writes ) = write_out_values(
            &ok_idents,
            self.com_out_args() );
        quote!(
            match #result {
                Ok( #ok_pattern ) => { #( #ok_writes );*; ::intercom::S_OK },
                Err( e ) => {
                    #( #err_writes );*;
                    ::intercom::return_hresult( e )
                },
            }
        )
    }

    fn com_out_args( &self ) -> Vec<RustArg> {
        get_out_args_for_result( &self.retval_ty )
    }
}

fn get_out_args_for_result( retval_ty : &Type ) -> Vec<RustArg> {

    match *retval_ty {

        // Tuples map to multiple out args, no [retval].
        Type::Tuple( ref t ) =>
            t.elems.iter()
                .enumerate()
                .map( |( idx, ty )| RustArg::new(
                                    Ident::from( format!( "__out{}", idx + 1) ),
                                    ty.clone() ) )
                .collect::<Vec<_>>(),
        _ => vec![ RustArg::new( Ident::from( "__out" ), retval_ty.clone() ) ],
    }
}

fn write_out_values(
    idents : &[Ident],
    out_args : Vec<RustArg>,
) -> ( Vec<Tokens>, Vec<Tokens> )
{
    let mut ok_tokens = vec![];
    let mut err_tokens = vec![];
    for ( ident, out_arg ) in idents.iter().zip( out_args ) {

        let arg_name = out_arg.name;
        let ok_value = out_arg.handler.rust_to_com( *ident );
        let err_value = out_arg.handler.default_value();
        ok_tokens.push( quote!( *#arg_name = #ok_value ) );
        err_tokens.push( quote!( *#arg_name = #err_value ) );
    }

    ( ok_tokens, err_tokens )
}

/// Gets the result as Rust types for a success return value.
fn get_rust_ok_values(
    out_args : Vec<RustArg>
) -> Vec<Tokens>
{
    let mut tokens = vec![];
    for out_arg in out_args {

        let arg_conversion = out_arg.handler.com_to_rust( out_arg.name );
        if arg_conversion.stack.is_some() {
            panic!( "Return values must be owned" );
        }
        let arg_value = arg_conversion.conversion;
        tokens.push( quote!( #arg_value ) );
    }
    tokens
}

/// Resolves the correct return handler to use.
pub fn get_return_handler(
    retval_ty : &Option< Type >,
    return_ty : &Option< Type >
) -> Result< Box<ReturnHandler>, () >
{
    Ok( match ( retval_ty, return_ty ) {
        ( &None, &None ) => Box::new( VoidHandler ),
        ( &None, &Some( ref ty ) )
            => Box::new( ReturnOnlyHandler( ty.clone() ) ),
        ( &Some( ref rv ), &Some( ref rt ) )
            => Box::new( ErrorResultHandler {
                retval_ty: rv.clone(),
                return_ty: rt.clone(),
            } ),

        // Unsupported return scheme. Note we are using Result::Err instead of
        // Option::None here because having no return handler is unsupported
        // error case.
        _ => return Err( () ),
    } )
}
<|endoftext|>


<commit_before>pub mod decode;
pub mod encode;
pub mod sync;
<commit_msg>Add baseband module doc<commit_after>//! Sychronization and symbol encoding/decoding of C4FM signal used by P25.

pub mod decode;
pub mod encode;
pub mod sync;
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Best_shuffle

//

extern crate permutohedron;
extern crate rand;

use std::cmp::{min, Ordering};
use std::env;
use rand::{thread_rng, Rng};
use std::str;

const WORDS: &'static [&'static str] = &["abracadabra", "seesaw", "elk", "grrrrrr", "up", "a"];

#[derive(Eq)]
struct Solution {
    original: String,
    shuffled: String,
    score: usize,
}

// Ordering trait implementations are only needed for the permutations method
impl PartialOrd for Solution {
    fn partial_cmp(&self, other: &Solution) -> Option<Ordering> {
        match (self.score, other.score) {
            (s, o) if s < o => Some(Ordering::Less),
            (s, o) if s > o => Some(Ordering::Greater),
            (s, o) if s == o => Some(Ordering::Equal),
            _ => None,
        }
    }
}

impl PartialEq for Solution {
    fn eq(&self, other: &Solution) -> bool {
        match (self.score, other.score) {
            (s, o) if s == o => true,
            _ => false,
        }
    }
}

impl Ord for Solution {
    fn cmp(&self, other: &Solution) -> Ordering {
        match (self.score, other.score) {
            (s, o) if s < o => Ordering::Less,
            (s, o) if s > o => Ordering::Greater,
            _ => Ordering::Equal,
        }
    }
}

fn _help() {
    println!("Usage: best_shuffle <word1> <word2> ...");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut words: Vec<String> = vec![];

    match args.len() {
        1 => {
            for w in WORDS.iter() {
                words.push(String::from(*w));
            }
        }
        _ => {
            for w in args.split_at(1).1 {
                words.push(w.clone());
            }
        }
    }

    let solutions = words.iter().map(|w| best_shuffle(w)).collect::<Vec<_>>();

    for s in solutions {
        println!("{}, {}, ({})", s.original, s.shuffled, s.score);
    }
}

// Implementation iterating over all permutations
fn _best_shuffle_perm(w: &String) -> Solution {
    let mut soln = Solution {
        original: w.clone(),
        shuffled: w.clone(),
        score: w.len(),
    };
    let w_bytes: Vec<u8> = w.clone().into_bytes();
    let mut permutocopy = w_bytes.clone();
    let mut permutations = permutohedron::Heap::new(&mut permutocopy);
    while let Some(p) = permutations.next_permutation() {
        // println!("testing permutation {:?}", str::from_utf8(p).unwrap());
        let hamm = hamming(&w_bytes, p);
        soln = min(soln,
                   Solution {
                       original: w.clone(),
                       shuffled: String::from(str::from_utf8(p).unwrap()),
                       score: hamm,
                   });
        // Accept the solution if score 0 found
        if hamm == 0 {
            break;
        }
    }
    soln
}

// Quadratic implementation
fn best_shuffle(w: &String) -> Solution {
    let w_bytes: Vec<u8> = w.clone().into_bytes();
    let mut shuffled_bytes: Vec<u8> = w.clone().into_bytes();

    // Shuffle once
    let sh: &mut [u8] = shuffled_bytes.as_mut_slice();
    thread_rng().shuffle(sh);

    // Swap wherever it doesn't decrease the score
    for i in 0..sh.len() {
        for j in 0..sh.len() {
            if (i == j) | (sh[i] == w_bytes[j]) | (sh[j] == w_bytes[i]) | (sh[i] == sh[j]) {
                continue;
            }
            sh.swap(i, j);
            break;
        }
    }

    let res = String::from(str::from_utf8(sh).unwrap());
    let res_bytes: Vec<u8> = res.clone().into_bytes();
    Solution {
        original: w.clone(),
        shuffled: res,
        score: hamming(&w_bytes, &res_bytes),
    }
}

fn hamming(w0: &Vec<u8>, w1: &Vec<u8>) -> usize {
    w0.iter().zip(w1.iter()).filter(|z| z.0 == z.1).count()
}

#[cfg(test)]
mod tests {
    use super::{best_shuffle, _best_shuffle_perm};

    #[test]
    fn test_best_shuffle_perm() {
        let mut s0 = _best_shuffle_perm(&String::from("seesaw"));
        assert_eq!(s0.score, 0);

        s0 = _best_shuffle_perm(&String::from("elk"));
        assert_eq!(s0.score, 0);

        s0 = _best_shuffle_perm(&String::from("grrrrrr"));
        assert_eq!(s0.score, 5);

        s0 = _best_shuffle_perm(&String::from("up"));
        assert_eq!(s0.shuffled, "pu");
        assert_eq!(s0.score, 0);

        s0 = _best_shuffle_perm(&String::from("a"));
        assert_eq!(s0.shuffled, "a");
        assert_eq!(s0.score, 1);
    }

    #[test]
    fn test_best_shuffle() {
        let mut s0 = best_shuffle(&String::from("abracadabra"));
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("seesaw"));
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("elk"));
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("grrrrrr"));
        assert_eq!(s0.score, 5);

        s0 = best_shuffle(&String::from("up"));
        assert_eq!(s0.shuffled, "pu");
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("a"));
        assert_eq!(s0.shuffled, "a");
        assert_eq!(s0.score, 1);
    }

}
<commit_msg>deleted empty comment<commit_after>// http://rosettacode.org/wiki/Best_shuffle

extern crate permutohedron;
extern crate rand;

use std::cmp::{min, Ordering};
use std::env;
use rand::{thread_rng, Rng};
use std::str;

const WORDS: &'static [&'static str] = &["abracadabra", "seesaw", "elk", "grrrrrr", "up", "a"];

#[derive(Eq)]
struct Solution {
    original: String,
    shuffled: String,
    score: usize,
}

// Ordering trait implementations are only needed for the permutations method
impl PartialOrd for Solution {
    fn partial_cmp(&self, other: &Solution) -> Option<Ordering> {
        match (self.score, other.score) {
            (s, o) if s < o => Some(Ordering::Less),
            (s, o) if s > o => Some(Ordering::Greater),
            (s, o) if s == o => Some(Ordering::Equal),
            _ => None,
        }
    }
}

impl PartialEq for Solution {
    fn eq(&self, other: &Solution) -> bool {
        match (self.score, other.score) {
            (s, o) if s == o => true,
            _ => false,
        }
    }
}

impl Ord for Solution {
    fn cmp(&self, other: &Solution) -> Ordering {
        match (self.score, other.score) {
            (s, o) if s < o => Ordering::Less,
            (s, o) if s > o => Ordering::Greater,
            _ => Ordering::Equal,
        }
    }
}

fn _help() {
    println!("Usage: best_shuffle <word1> <word2> ...");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut words: Vec<String> = vec![];

    match args.len() {
        1 => {
            for w in WORDS.iter() {
                words.push(String::from(*w));
            }
        }
        _ => {
            for w in args.split_at(1).1 {
                words.push(w.clone());
            }
        }
    }

    let solutions = words.iter().map(|w| best_shuffle(w)).collect::<Vec<_>>();

    for s in solutions {
        println!("{}, {}, ({})", s.original, s.shuffled, s.score);
    }
}

// Implementation iterating over all permutations
fn _best_shuffle_perm(w: &String) -> Solution {
    let mut soln = Solution {
        original: w.clone(),
        shuffled: w.clone(),
        score: w.len(),
    };
    let w_bytes: Vec<u8> = w.clone().into_bytes();
    let mut permutocopy = w_bytes.clone();
    let mut permutations = permutohedron::Heap::new(&mut permutocopy);
    while let Some(p) = permutations.next_permutation() {
        // println!("testing permutation {:?}", str::from_utf8(p).unwrap());
        let hamm = hamming(&w_bytes, p);
        soln = min(soln,
                   Solution {
                       original: w.clone(),
                       shuffled: String::from(str::from_utf8(p).unwrap()),
                       score: hamm,
                   });
        // Accept the solution if score 0 found
        if hamm == 0 {
            break;
        }
    }
    soln
}

// Quadratic implementation
fn best_shuffle(w: &String) -> Solution {
    let w_bytes: Vec<u8> = w.clone().into_bytes();
    let mut shuffled_bytes: Vec<u8> = w.clone().into_bytes();

    // Shuffle once
    let sh: &mut [u8] = shuffled_bytes.as_mut_slice();
    thread_rng().shuffle(sh);

    // Swap wherever it doesn't decrease the score
    for i in 0..sh.len() {
        for j in 0..sh.len() {
            if (i == j) | (sh[i] == w_bytes[j]) | (sh[j] == w_bytes[i]) | (sh[i] == sh[j]) {
                continue;
            }
            sh.swap(i, j);
            break;
        }
    }

    let res = String::from(str::from_utf8(sh).unwrap());
    let res_bytes: Vec<u8> = res.clone().into_bytes();
    Solution {
        original: w.clone(),
        shuffled: res,
        score: hamming(&w_bytes, &res_bytes),
    }
}

fn hamming(w0: &Vec<u8>, w1: &Vec<u8>) -> usize {
    w0.iter().zip(w1.iter()).filter(|z| z.0 == z.1).count()
}

#[cfg(test)]
mod tests {
    use super::{best_shuffle, _best_shuffle_perm};

    #[test]
    fn test_best_shuffle_perm() {
        let mut s0 = _best_shuffle_perm(&String::from("seesaw"));
        assert_eq!(s0.score, 0);

        s0 = _best_shuffle_perm(&String::from("elk"));
        assert_eq!(s0.score, 0);

        s0 = _best_shuffle_perm(&String::from("grrrrrr"));
        assert_eq!(s0.score, 5);

        s0 = _best_shuffle_perm(&String::from("up"));
        assert_eq!(s0.shuffled, "pu");
        assert_eq!(s0.score, 0);

        s0 = _best_shuffle_perm(&String::from("a"));
        assert_eq!(s0.shuffled, "a");
        assert_eq!(s0.score, 1);
    }

    #[test]
    fn test_best_shuffle() {
        let mut s0 = best_shuffle(&String::from("abracadabra"));
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("seesaw"));
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("elk"));
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("grrrrrr"));
        assert_eq!(s0.score, 5);

        s0 = best_shuffle(&String::from("up"));
        assert_eq!(s0.shuffled, "pu");
        assert_eq!(s0.score, 0);

        s0 = best_shuffle(&String::from("a"));
        assert_eq!(s0.shuffled, "a");
        assert_eq!(s0.score, 1);
    }

}
<|endoftext|>


<commit_before>extern crate brotli;
extern crate core;
use std::env;
use std::io;
use std::io::{Read, Write};
use std::path::Path;
use std::fs::File;
use brotli::BrotliResult;
use brotli::concat::BroCatli;
fn usage() {
    writeln!(&mut ::std::io::stderr(), "Usage: [-w<window_size>] filename0 filename1 filename2...").unwrap();
}
fn read_no_interrupt<R:Read>(r: &mut R, buf: &mut [u8]) -> Result<usize, io::Error> {
    loop {
        match r.read(buf) {
          Err(e) => {
              match e.kind() {
                  io::ErrorKind::Interrupted => continue,
                  _ => return Err(e),
              }
          }
            Ok(cur_read) => return Ok(cur_read),
        }
    }
}

fn write_no_interrupt<W:Write>(w: &mut W, mut buf: &[u8]) -> Result<usize, io::Error> {
    let mut total_read = 0usize;
    loop {
        match w.write(buf) {
            Err(e) => {
                match e.kind() {
                    io::ErrorKind::Interrupted => continue,
                    _ => return Err(e),
                }
            },
            Ok(cur_read) => {
                buf = &buf[cur_read..];
                total_read += cur_read;
                if buf.len() == 0 {
                    return Ok(total_read);
                }
            },
        }
    }
}

fn main() {
    let mut window_size: Option<u8> = None;
    let mut double_dash = false;
    let mut buffer_size = 4096usize;
    let mut filenames = Vec::<String>::new();
    let mut ostream = io::stdout();
    if env::args_os().len() > 1 {
        for argument in env::args().skip(1) {
            if argument.starts_with("-w") && !double_dash {
                window_size = Some(argument.trim_matches('-').trim_matches('w').parse::<i32>().unwrap() as u8);
                continue;
            }
            if argument.starts_with("-bs") && !double_dash {
                buffer_size = argument.trim_matches('-').trim_matches('b').trim_matches('s').parse::<usize>().unwrap();
                continue;
            }
            if argument == "--" {
                double_dash = true;
                continue;
            }
            filenames.push(argument);
        }
    } else {
        usage();
        return;
    }
    let mut ibuffer = vec![0u8; buffer_size];
    let mut obuffer = vec![0u8; buffer_size];
    let mut ooffset = 0;
    let mut ioffset;
    let mut bro_cat_li = match window_size {
        Some(ws) => BroCatli::new_with_window_size(ws),
        None => BroCatli::new(),
    };
    for filename in filenames {
        bro_cat_li.new_brotli_file();
        let mut input_file = match File::open(&Path::new(&filename)) {
            Err(why) => panic!("couldn't open {:}\n{:}", filename, why),
            Ok(file) => file,
        };
        loop {
            ioffset = 0;
            match read_no_interrupt(&mut input_file, &mut ibuffer[..]) {
                Err(e) => panic!(e),
                Ok(cur_read) => {
                    if cur_read == 0 {
                        break;
                    }
                    loop {
                        match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                                &mut obuffer[..], &mut ooffset) {
                            BrotliResult::ResultFailure => {
                                panic!("Failed to concatenate files on ".to_string() + &filename);
                            },
                            BrotliResult::NeedsMoreOutput => {
                                match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
                                    Err(why) => panic!("couldn't write to {:?}\n{:}", ostream, why),
                                    Ok(count) => {assert_eq!(count, ooffset);},
                                }
                                ooffset = 0;
                            },
                            BrotliResult::NeedsMoreInput => {
                                break;
                            },
                            BrotliResult::ResultSuccess => {
                                panic!("Unexpected state: Success when streaming before finish");
                            }
                        }

                    }
                }
            }
        }
    }
    loop {
        match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
            BrotliResult::NeedsMoreOutput => {
                match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write to {:?}\n{:}", ostream, why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
            },
            BrotliResult::NeedsMoreInput => {
                panic!("Unexpected EOF");
            },
            BrotliResult::ResultSuccess => {
                if ooffset != 0 {
                    match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
                        Err(why) => panic!("couldn't write to {:?}\n{:}", ostream, why),
                        Ok(count) => {assert_eq!(count, ooffset);},
                    }
                }
                break;
            }
            BrotliResult::ResultFailure => {
                panic!("Failed to terminate concatenation")
            }
        }
    }
}
<commit_msg>some 1.8.0 compat features<commit_after>extern crate brotli;
extern crate core;
use std::env;
use std::io;
use std::io::{Read, Write};
use std::path::Path;
use std::fs::File;
use brotli::BrotliResult;
use brotli::concat::BroCatli;
fn usage() {
    writeln!(&mut ::std::io::stderr(), "Usage: [-w<window_size>] filename0 filename1 filename2...").unwrap();
}
fn read_no_interrupt<R:Read>(r: &mut R, buf: &mut [u8]) -> Result<usize, io::Error> {
    loop {
        match r.read(buf) {
          Err(e) => {
              match e.kind() {
                  io::ErrorKind::Interrupted => continue,
                  _ => return Err(e),
              }
          }
            Ok(cur_read) => return Ok(cur_read),
        }
    }
}

fn write_no_interrupt<W:Write>(w: &mut W, mut buf: &[u8]) -> Result<usize, io::Error> {
    let mut total_read = 0usize;
    loop {
        match w.write(buf) {
            Err(e) => {
                match e.kind() {
                    io::ErrorKind::Interrupted => continue,
                    _ => return Err(e),
                }
            },
            Ok(cur_read) => {
                buf = &buf[cur_read..];
                total_read += cur_read;
                if buf.len() == 0 {
                    return Ok(total_read);
                }
            },
        }
    }
}

fn main() {
    let mut window_size: Option<u8> = None;
    let mut double_dash = false;
    let mut buffer_size = 4096usize;
    let mut filenames = Vec::<String>::new();
    let mut ostream = io::stdout();
    if env::args_os().len() > 1 {
        for argument in env::args().skip(1) {
            if argument.starts_with("-w") && !double_dash {
                window_size = Some(argument.trim_matches('-').trim_matches('w').parse::<i32>().unwrap() as u8);
                continue;
            }
            if argument.starts_with("-bs") && !double_dash {
                buffer_size = argument.trim_matches('-').trim_matches('b').trim_matches('s').parse::<usize>().unwrap();
                continue;
            }
            if argument == "--" {
                double_dash = true;
                continue;
            }
            filenames.push(argument);
        }
    } else {
        usage();
        return;
    }
    let mut ibuffer = vec![0u8; buffer_size];
    let mut obuffer = vec![0u8; buffer_size];
    let mut ooffset = 0;
    let mut ioffset;
    let mut bro_cat_li = match window_size {
        Some(ws) => BroCatli::new_with_window_size(ws),
        None => BroCatli::new(),
    };
    for filename in filenames {
        bro_cat_li.new_brotli_file();
        let mut input_file = match File::open(&Path::new(&filename)) {
            Err(why) => panic!("couldn't open {:}\n{:}", filename, why),
            Ok(file) => file,
        };
        loop {
            ioffset = 0;
            match read_no_interrupt(&mut input_file, &mut ibuffer[..]) {
                Err(e) => panic!(e),
                Ok(cur_read) => {
                    if cur_read == 0 {
                        break;
                    }
                    loop {
                        match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                                &mut obuffer[..], &mut ooffset) {
                            BrotliResult::ResultFailure => {
                                panic!("Failed to concatenate files on ".to_string() + &filename);
                            },
                            BrotliResult::NeedsMoreOutput => {
                                match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
                                    Err(why) => panic!("couldn't write: {:}", why),
                                    Ok(count) => {assert_eq!(count, ooffset);},
                                }
                                ooffset = 0;
                            },
                            BrotliResult::NeedsMoreInput => {
                                break;
                            },
                            BrotliResult::ResultSuccess => {
                                panic!("Unexpected state: Success when streaming before finish");
                            }
                        }

                    }
                }
            }
        }
    }
    loop {
        match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
            BrotliResult::NeedsMoreOutput => {
                match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write to {:?}\n{:}", ostream, why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
            },
            BrotliResult::NeedsMoreInput => {
                panic!("Unexpected EOF");
            },
            BrotliResult::ResultSuccess => {
                if ooffset != 0 {
                    match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
                        Err(why) => panic!("couldn't write to {:?}\n{:}", ostream, why),
                        Ok(count) => {assert_eq!(count, ooffset);},
                    }
                }
                break;
            }
            BrotliResult::ResultFailure => {
                panic!("Failed to terminate concatenation")
            }
        }
    }
}
<|endoftext|>


<commit_before>//! An unbounded set of streams

use std::fmt::{self, Debug};
use std::pin::Pin;
use std::marker::Unpin;

use futures_core::{Poll, Stream, FusedStream};
use futures_core::task::LocalWaker;

use crate::stream::{StreamExt, StreamFuture, FuturesUnordered};

/// An unbounded set of streams
///
/// This "combinator" provides the ability to maintain a set of streams
/// and drive them all to completion.
///
/// Streams are pushed into this set and their realized values are
/// yielded as they become ready. Streams will only be polled when they
/// generate notifications. This allows to coordinate a large number of streams.
///
/// Note that you can create a ready-made `SelectAll` via the
/// `select_all` function in the `stream` module, or you can start with an
/// empty set with the `SelectAll::new` constructor.
#[must_use = "streams do nothing unless polled"]
pub struct SelectAll<St> {
    inner: FuturesUnordered<StreamFuture<St>>,
}

impl<St: Debug> Debug for SelectAll<St> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "SelectAll {{ ... }}")
    }
}

impl<St: Stream + Unpin> SelectAll<St> {
    /// Constructs a new, empty `SelectAll`
    ///
    /// The returned `SelectAll` does not contain any streams and, in this
    /// state, `SelectAll::poll` will return `Poll::Ready(None)`.
    #[allow(clippy::new_without_default_derive)]
    pub fn new() -> SelectAll<St> {
        SelectAll { inner: FuturesUnordered::new() }
    }

    /// Returns the number of streams contained in the set.
    ///
    /// This represents the total number of in-flight streams.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns `true` if the set contains no streams
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Push a stream into the set.
    ///
    /// This function submits the given stream to the set for managing. This
    /// function will not call `poll` on the submitted stream. The caller must
    /// ensure that `SelectAll::poll` is called in order to receive task
    /// notifications.
    pub fn push(&mut self, stream: St) {
        self.inner.push(stream.into_future());
    }
}

impl<St: Stream + Unpin> Stream for SelectAll<St> {
    type Item = St::Item;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<Self::Item>> {
        match self.inner.poll_next_unpin(lw) {
            Poll::Pending => Poll::Pending,
            Poll::Ready(Some((Some(item), remaining))) => {
                self.push(remaining);
                Poll::Ready(Some(item))
            }
            Poll::Ready(Some((None, _))) => {
                // FuturesUnordered thinks it isn't terminated
                // because it yielded a Some. Here we poll it
                // so it can realize it is terminated.
                self.inner.poll_next_unpin(lw);
                Poll::Ready(None)
            }
            Poll::Ready(_) => Poll::Ready(None),
        }
    }
}

impl<St: Stream + Unpin> FusedStream for SelectAll<St> {
    fn is_terminated(&self) -> bool {
        self.inner.is_terminated()
    }
}

/// Convert a list of streams into a `Stream` of results from the streams.
///
/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.)
/// and bundles them together into a single stream.
/// The stream will yield items as they become available on the underlying
/// streams internally, in the order they become available.
///
/// Note that the returned set can also be used to dynamically push more
/// futures into the set as they become available.
pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
    where I: IntoIterator,
          I::Item: Stream + Unpin
{
    let mut set = SelectAll::new();

    for stream in streams {
        set.push(stream);
    }

    set
}
<commit_msg>impl Default for SelectAll<commit_after>//! An unbounded set of streams

use std::fmt::{self, Debug};
use std::pin::Pin;
use std::marker::Unpin;

use futures_core::{Poll, Stream, FusedStream};
use futures_core::task::LocalWaker;

use crate::stream::{StreamExt, StreamFuture, FuturesUnordered};

/// An unbounded set of streams
///
/// This "combinator" provides the ability to maintain a set of streams
/// and drive them all to completion.
///
/// Streams are pushed into this set and their realized values are
/// yielded as they become ready. Streams will only be polled when they
/// generate notifications. This allows to coordinate a large number of streams.
///
/// Note that you can create a ready-made `SelectAll` via the
/// `select_all` function in the `stream` module, or you can start with an
/// empty set with the `SelectAll::new` constructor.
#[must_use = "streams do nothing unless polled"]
pub struct SelectAll<St> {
    inner: FuturesUnordered<StreamFuture<St>>,
}

impl<St: Debug> Debug for SelectAll<St> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "SelectAll {{ ... }}")
    }
}

impl<St: Stream + Unpin> SelectAll<St> {
    /// Constructs a new, empty `SelectAll`
    ///
    /// The returned `SelectAll` does not contain any streams and, in this
    /// state, `SelectAll::poll` will return `Poll::Ready(None)`.
    pub fn new() -> SelectAll<St> {
        SelectAll { inner: FuturesUnordered::new() }
    }

    /// Returns the number of streams contained in the set.
    ///
    /// This represents the total number of in-flight streams.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns `true` if the set contains no streams
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Push a stream into the set.
    ///
    /// This function submits the given stream to the set for managing. This
    /// function will not call `poll` on the submitted stream. The caller must
    /// ensure that `SelectAll::poll` is called in order to receive task
    /// notifications.
    pub fn push(&mut self, stream: St) {
        self.inner.push(stream.into_future());
    }
}

impl<St: Stream + Unpin> Default for SelectAll<St> {
    fn default() -> SelectAll<St> {
        SelectAll::new()
    }
}

impl<St: Stream + Unpin> Stream for SelectAll<St> {
    type Item = St::Item;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<Self::Item>> {
        match self.inner.poll_next_unpin(lw) {
            Poll::Pending => Poll::Pending,
            Poll::Ready(Some((Some(item), remaining))) => {
                self.push(remaining);
                Poll::Ready(Some(item))
            }
            Poll::Ready(Some((None, _))) => {
                // FuturesUnordered thinks it isn't terminated
                // because it yielded a Some. Here we poll it
                // so it can realize it is terminated.
                self.inner.poll_next_unpin(lw);
                Poll::Ready(None)
            }
            Poll::Ready(_) => Poll::Ready(None),
        }
    }
}

impl<St: Stream + Unpin> FusedStream for SelectAll<St> {
    fn is_terminated(&self) -> bool {
        self.inner.is_terminated()
    }
}

/// Convert a list of streams into a `Stream` of results from the streams.
///
/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.)
/// and bundles them together into a single stream.
/// The stream will yield items as they become available on the underlying
/// streams internally, in the order they become available.
///
/// Note that the returned set can also be used to dynamically push more
/// futures into the set as they become available.
pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
    where I: IntoIterator,
          I::Item: Stream + Unpin
{
    let mut set = SelectAll::new();

    for stream in streams {
        set.push(stream);
    }

    set
}
<|endoftext|>