<commit_before>extern crate openssl;
extern crate rust_base58;
extern crate rustc_serialize;
#[cfg(test)] extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::{FromBase58, ToBase58};

#[derive(Copy, Clone)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_code(code: u8) -> Option<HashType> {
        match code {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    fn digest_len(&self) -> u8 {
        match *self {
            SHA1     => 20,
            SHA2_256 => 32,
            SHA2_512 => 64,
            SHA3     => 64,
            BLAKE2B  => 64,
            BLAKE2S  => 32,
        }
    }

    fn code(&self) -> u8 {
        *self as u8
    }

    fn to_str(&self) -> &'static str {
        match *self {
            SHA1     => "sha1",
            SHA2_256 => "sha2-256",
            SHA2_512 => "sha2-512",
            SHA3     => "sha3",
            BLAKE2B  => "blake2b",
            BLAKE2S  => "blake2s",
        }
    }
}

/// Hashes the `data` with the function described by `hash_type` and returns the result
/// as a Multihash.
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1     => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type.code()).unwrap()
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Multihash {
    bytes: Vec<u8>
}

impl Multihash {
    /// Construct a multihash from a base58 string by parsing it into bytes. Verifies
    /// that the bytes are valid according to the Multihash format.
    pub fn from_base58_str(s: &str) -> Result<Multihash, String> {
        let bytes = try!(s.from_base58()
                          .map_err(|e| format!("Error parsing base58 string: {}", e)));

        let hash_code = bytes[0];

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        if !is_app_code(hash_code) {
            let hash_type = HashType::from_code(hash_code).unwrap();
            let expected_digest_len = hash_type.digest_len();
            if expected_digest_len != bytes[1] {
                return Err(format!("For hash function {}, expected digest length {}, but \
                                    found digest length {}", hash_type.to_str(),
                                    expected_digest_len, bytes[1]));
            }
        }

        if (bytes.len() - 2) as u8 != bytes[1] {
            return Err(format!("Hash digest is {} bytes, which does not match the stated \
                                digest length {}", bytes.len() - 2, bytes[1]));
        }

        Ok(Multihash::from_vec(bytes))
    }

    /// Create a Multihash directly from a vector of bytes. Does not verify that the
    /// bytes are a valid Multihash.
    pub fn from_vec(vec: Vec<u8>) -> Multihash {
        Multihash { bytes: vec }
    }

    pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] }

    pub fn into_bytes(self) -> Vec<u8> { self.bytes }

    /// Construct a Multihash out of the hash digest and hash function code
    pub fn encode<'a>(digest: &'a [u8], hash_code: u8) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_code);
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash::from_vec(v))
    }

    // TODO: evaluate whether this function makes sense
    /*
    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.bytes.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.bytes[1] {
                return Err(DecodeError::InvalidDigestLength(self.bytes[1], digest_len));
            }
        }

        let fn_code = match HashType::from_code(self.bytes[0]) {
            None => return Err(DecodeError::UnknownCode(self.bytes[0])),
            Some(code) => code,
        };

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: fn_code.to_str(),
            length: self.bytes[1],
            digest: &self.bytes[2..],
        };
        Ok(decoded)

    }
    */

    pub fn to_base58_string(&self) -> String {
        self.bytes.to_base58()
    }
}

impl rustc_serialize::Encodable for Multihash {
    fn encode<S>(&self, s: &mut S) -> Result<(), S::Error> where
        S: rustc_serialize::Encoder
    {
        self.to_base58_string().encode(s)
    }
}

fn is_valid_code(code: u8) -> bool {
    is_app_code(code) || HashType::from_code(code).is_some()
}

fn is_app_code(code: u8) -> bool {
    code <= 0x0f
}

/*
pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}
*/

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType};
    use rustc_serialize::hex::FromHex;
    use rust_base58::ToBase58;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.code());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type.code()).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    /*
    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = case.hash_type.to_str();

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }
    */

    #[test]
    fn test_from_base58_str() {
        assert!(Multihash::from_base58_str("Invalid base58!!!").is_err());

        // digest length of SHA1 is 20, not 5
        let x = &[0x11, 5, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        // mismatch between stated digest length and actual digest length
        let x = &[0x11, 20, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_ok());

        let x = "QmR6XorNYAywK4q1dRiRN1gmvfLcx3ccBv68iGtAqon9tt";
        assert!(Multihash::from_base58_str(x).is_ok());
    }
}
<commit_msg>Implement rustc_serialize::hex::ToHex for Multihash<commit_after>extern crate openssl;
extern crate rust_base58;
extern crate rustc_serialize;
#[cfg(test)] extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::{FromBase58, ToBase58};

#[derive(Copy, Clone)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_code(code: u8) -> Option<HashType> {
        match code {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    fn digest_len(&self) -> u8 {
        match *self {
            SHA1     => 20,
            SHA2_256 => 32,
            SHA2_512 => 64,
            SHA3     => 64,
            BLAKE2B  => 64,
            BLAKE2S  => 32,
        }
    }

    fn code(&self) -> u8 {
        *self as u8
    }

    fn to_str(&self) -> &'static str {
        match *self {
            SHA1     => "sha1",
            SHA2_256 => "sha2-256",
            SHA2_512 => "sha2-512",
            SHA3     => "sha3",
            BLAKE2B  => "blake2b",
            BLAKE2S  => "blake2s",
        }
    }
}

/// Hashes the `data` with the function described by `hash_type` and returns the result
/// as a Multihash.
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1     => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type.code()).unwrap()
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Multihash {
    bytes: Vec<u8>
}

impl Multihash {
    /// Construct a multihash from a base58 string by parsing it into bytes. Verifies
    /// that the bytes are valid according to the Multihash format.
    pub fn from_base58_str(s: &str) -> Result<Multihash, String> {
        let bytes = try!(s.from_base58()
                          .map_err(|e| format!("Error parsing base58 string: {}", e)));

        let hash_code = bytes[0];

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        if !is_app_code(hash_code) {
            let hash_type = HashType::from_code(hash_code).unwrap();
            let expected_digest_len = hash_type.digest_len();
            if expected_digest_len != bytes[1] {
                return Err(format!("For hash function {}, expected digest length {}, but \
                                    found digest length {}", hash_type.to_str(),
                                    expected_digest_len, bytes[1]));
            }
        }

        if (bytes.len() - 2) as u8 != bytes[1] {
            return Err(format!("Hash digest is {} bytes, which does not match the stated \
                                digest length {}", bytes.len() - 2, bytes[1]));
        }

        Ok(Multihash::from_vec(bytes))
    }

    /// Create a Multihash directly from a vector of bytes. Does not verify that the
    /// bytes are a valid Multihash.
    pub fn from_vec(vec: Vec<u8>) -> Multihash {
        Multihash { bytes: vec }
    }

    pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] }

    pub fn into_bytes(self) -> Vec<u8> { self.bytes }

    /// Construct a Multihash out of the hash digest and hash function code
    pub fn encode<'a>(digest: &'a [u8], hash_code: u8) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_code);
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash::from_vec(v))
    }

    // TODO: evaluate whether this function makes sense
    /*
    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.bytes.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.bytes[1] {
                return Err(DecodeError::InvalidDigestLength(self.bytes[1], digest_len));
            }
        }

        let fn_code = match HashType::from_code(self.bytes[0]) {
            None => return Err(DecodeError::UnknownCode(self.bytes[0])),
            Some(code) => code,
        };

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: fn_code.to_str(),
            length: self.bytes[1],
            digest: &self.bytes[2..],
        };
        Ok(decoded)

    }
    */

    pub fn to_base58_string(&self) -> String {
        self.bytes.to_base58()
    }
}

impl rustc_serialize::Encodable for Multihash {
    fn encode<S>(&self, s: &mut S) -> Result<(), S::Error> where
        S: rustc_serialize::Encoder
    {
        self.to_base58_string().encode(s)
    }
}

impl rustc_serialize::hex::ToHex for Multihash {
    fn to_hex(&self) -> String {
        self.bytes.to_hex()
    }
}

fn is_valid_code(code: u8) -> bool {
    is_app_code(code) || HashType::from_code(code).is_some()
}

fn is_app_code(code: u8) -> bool {
    code <= 0x0f
}

/*
pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}
*/

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType};
    use rustc_serialize::hex::FromHex;
    use rust_base58::ToBase58;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.code());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type.code()).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    /*
    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = case.hash_type.to_str();

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }
    */

    #[test]
    fn test_from_base58_str() {
        assert!(Multihash::from_base58_str("Invalid base58!!!").is_err());

        // digest length of SHA1 is 20, not 5
        let x = &[0x11, 5, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        // mismatch between stated digest length and actual digest length
        let x = &[0x11, 20, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_ok());

        let x = "QmR6XorNYAywK4q1dRiRN1gmvfLcx3ccBv68iGtAqon9tt";
        assert!(Multihash::from_base58_str(x).is_ok());
    }
}
<|endoftext|>


<commit_before>//! Straight-forward functions and types for basic data parallel
//! operations.
//!
//! This library provides a few building blocks for operating on data
//! in parallel, particularly iterators. At the moment, it is not
//! designed to be robust or eke out every last drop of performance,
//! but rather explore some ways in which Rust's type system allows
//! for some fairly fancy things to be written with a guarantee of
//! safety, all without a garbage collector.
//!
//! The only dependency is `std` and the basic functionality has no
//! `unsafe` code at all (the thread pool does use unsafe). Other than
//! the pool, parallelism is built directly from the functionality
//! provided by `std::thread` and `std::sync` and leverages their
//! correctness to automatically ensure the correctness of this
//! library (at the memory safety level).
//!
//! The core design is to simply allow for operations that could occur
//! on a single thread to execute on many, it is not intending to
//! serve as a hard boundary between threads; in particular, if
//! something (a `panic!`) would take down the main thread when run
//! sequentially, it will also take down the main thread (eventually)
//! when run using the functions in this library.
//!
//! On the point of performance and robustness, the top level
//! functions do no thread pooling and so everything essentially
//! spawns a new thread for each element, which is definitely
//! suboptimal for many reasons. Fortunately, not all is lost, the
//! functionality is designed to be as generic as possible, so the
//! iterator functions work with many many iterators, e.g. instead of
//! executing a thread on every element of a vector individually, a
//! user can divide that vector into disjoint sections and spread
//! those across much fewer threads (e.g. [the `chunks`
//! method](http://doc.rust-lang.org/nightly/std/slice/trait.SliceExt.html#tymethod.chunks)).
//!
//! Further, the thread pooling that does exist has a lot of
//! synchronisation overhead, and so is actually rarely a performance
//! improvement (although it is a robustness improvement over the
//! top-level functions, since it limits the number of threads that
//! will be spawned).
//!
//! Either way, **this is not recommended for general use**.
//!
//! # `simple_parallel` and stability
//!
//! This library is built around the same idea as
//! `std::thread::scoped`, and some functions suffer from [its
//! problems](https://github.com/rust-lang/rust/issues/24292). In
//! particular, there are several functions that either use `scoped`
//! directly, or expose a similar API.
//!
//! The version of this library usable with Rust 1.0 only exposes
//! `Pool`, which manually implement the same functionality as
//! `std::thread::scoped`, but do it in a way that avoids feature
//! gates. However, the `map` and `unordered_map` methods have the
//! same unsafety problem and so are marked `unsafe` (at least until
//! the standard library has a solution).
//!
//! The APIs that need the `scoped` functionality are still available
//! only nightly, with the `simple_parallel/unstable` feature.
//!
//! # Usage
//!
//! This is [available on
//! crates.io](https://crates.io/crates/simple_parallel). Add this to
//! your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! simple_parallel = "0.1"
//! ```
//!
//! The latest development version can be obtained [on
//! GitHub](https://github.com/huonw/simple_parallel).
//!
//! # Examples
//!
//! Initialise an array, in parallel.
//!
//! ```rust
//! # #[cfg(feature = "unstable")] fn foo() {
//! let mut data = [0; 10];
//! // fill the array, with one thread for each element:
//! simple_parallel::for_(data.iter_mut().enumerate(), |(i, elem)| {
//!     *elem = i as i32;
//! });
//! # }
//!
//! # let mut data = [0; 10];
//! // now adjust that data, with a threadpool:
//! let mut pool = simple_parallel::Pool::new(4);
//! pool.for_(data.iter_mut(), |elem| *elem *= 2);
//! ```
//!
//! Transform each element of an ordered map in a fancy way, in
//! parallel, with `map` (`map` ensures the output order matches the
//! input order, unlike `unordered_map`),
//!
//! ```rust
//! #[cfg(feature = "unstable")] fn foo() {
//! use std::collections::BTreeMap;
//!
//! let mut map = BTreeMap::new();
//! map.insert('a', 1);
//! map.insert('x', 55);
//!
//! let f = |(&c, &elem): (&char, _)| {
//!     let mut x = elem  * c as i32;
//!     // ... something complicated and expensive ...
//!     return x as f64
//! };
//!
//! // (`IntoIterator` is used, so "direct" iteration like this is fine.)
//! let par_iter = simple_parallel::map(&map, &f);
//!
//! // the computation is executing on several threads in the
//! // background, so that elements are hopefully ready as soon as
//! // possible.
//!
//! for value in par_iter {
//!     println!("I computed {}", value);
//! }
//! # }
//! ```
//!
//! Sum an arbitrarily long slice, in parallel, by summing subsections and adding
//! everything to a shared mutex, stored on the stack of the main
//! thread. (A parallel fold is currently missing, hence the mutex.)
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const NUM_CHUNKS: usize = 8;
//!
//! # #[cfg(feature = "unstable")]
//! fn sum(x: &[f64]) -> f64 {
//!     // (round up)
//!     let elements_per_chunk = (x.len() + NUM_CHUNKS - 1) / NUM_CHUNKS;
//!
//!     let total = Mutex::new(0.0);
//!     simple_parallel::for_(x.chunks(elements_per_chunk), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! Alternatively, one could use a thread pool, and assign an absolute
//! number of elements to each subsection and let the pool manage
//! distributing the work among threads, instead of being forced to
//! computing the length of the subsections to limit the number of
//! threads spawned.
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const ELEMS_PER_JOB: usize = 1_000;
//!
//! fn pooled_sum(pool: &mut simple_parallel::Pool, x: &[f64]) -> f64 {
//!     let total = Mutex::new(0.0);
//!     pool.for_(x.chunks(ELEMS_PER_JOB), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! A sketch of a very simple recursive parallel merge-sort, using
//! `both` to handle the recursion. (A working implementation may
//! really need some temporary buffers to mangle the data, but the key
//! point is `both` naturally running things in parallel.)
//!
//! ```rust
//! # #[cfg(feature = "unstable")] fn foo() {
//! /// Merges the two sorted runs `left` and `right`.
//! /// That is, after `merge(left, right)`,
//! ///
//! ///    left[0] <= left[1] <= ... <= left[last] <= right[0] <= ...
//! fn merge<T: Ord>(left: &mut [T], right: &mut [T]) {
//!     // magic (but non-parallel, so boring)
//! }
//!
//! fn parallel_merge_sort<T: Ord + Send>(x: &mut [T]) {
//!    // base case
//!    if x.len() <= 1 { return }
//!
//!    // get two disjoint halves of the `x`,
//!    let half = x.len() / 2;
//!    let (left, right) = x.split_at_mut(half);
//!    // and sort them recursively, in parallel
//!    simple_parallel::both(&mut *left, &mut *right, |v| parallel_merge_sort(v));
//!
//!    // now combine the two sorted halves
//!    merge(left, right)
//! }
//! # }
//! ```
//!
//! The [`examples`
//! folder](https://github.com/huonw/simple_parallel/tree/master/examples)
//! contains more intricate example(s), such as a parallel fast
//! Fourier transform implementation (it really works, and the
//! parallelism does buy something... when tuned).
#![cfg_attr(feature = "unstable", feature(scoped))]

#[cfg(feature = "unstable")]
use std::thread;
#[cfg(feature = "unstable")]
use std::iter::IntoIterator;

#[cfg(feature = "unstable")]
mod maps;

mod fnbox;

pub mod pool;

pub mod one_to_one {
    #[cfg(feature = "unstable")]
    pub use maps::{unordered_map, UnorderedParMap, map, ParMap};
}

#[cfg(feature = "unstable")]
pub use one_to_one::{map, unordered_map};

pub use pool::Pool;

/// Execute `f` on each element of `iter`, in their own `scoped`
/// thread.
///
/// If `f` panics, so does `for_`. If this occurs, the number of
/// elements of `iter` that have had `f` called on them is
/// unspecified.
#[cfg(feature = "unstable")]
pub fn for_<I: IntoIterator, F>(iter: I, ref f: F)
    where I::Item: Send, F: Fn(I::Item) + Sync
{
    let _guards: Vec<_> = iter.into_iter().map(|elem| {
        thread::scoped(move || {
            f(elem)
        })
    }).collect();
}

/// Execute `f` on both `x` and `y`, in parallel, returning the
/// result.
///
/// This is the same (including panic semantics) as `(f(x), f(y))`, up
/// to ordering. It is designed to be used for divide-and-conquer
/// algorithms.
#[cfg(feature = "unstable")]
pub fn both<T, U, F>(x: T, y: T, ref f: F) -> (U, U)
    where T: Send,
          U: Send,
          F: Sync + Fn(T) -> U
{
    let guard = thread::scoped(move || f(y));
    let a = f(x);
    let b = guard.join();
    (a, b)
}
<commit_msg>Update docs to 0.2.<commit_after>//! Straight-forward functions and types for basic data parallel
//! operations.
//!
//! This library provides a few building blocks for operating on data
//! in parallel, particularly iterators. At the moment, it is not
//! designed to be robust or eke out every last drop of performance,
//! but rather explore some ways in which Rust's type system allows
//! for some fairly fancy things to be written with a guarantee of
//! safety, all without a garbage collector.
//!
//! The only dependency is `std` and the basic functionality has no
//! `unsafe` code at all (the thread pool does use unsafe). Other than
//! the pool, parallelism is built directly from the functionality
//! provided by `std::thread` and `std::sync` and leverages their
//! correctness to automatically ensure the correctness of this
//! library (at the memory safety level).
//!
//! The core design is to simply allow for operations that could occur
//! on a single thread to execute on many, it is not intending to
//! serve as a hard boundary between threads; in particular, if
//! something (a `panic!`) would take down the main thread when run
//! sequentially, it will also take down the main thread (eventually)
//! when run using the functions in this library.
//!
//! On the point of performance and robustness, the top level
//! functions do no thread pooling and so everything essentially
//! spawns a new thread for each element, which is definitely
//! suboptimal for many reasons. Fortunately, not all is lost, the
//! functionality is designed to be as generic as possible, so the
//! iterator functions work with many many iterators, e.g. instead of
//! executing a thread on every element of a vector individually, a
//! user can divide that vector into disjoint sections and spread
//! those across much fewer threads (e.g. [the `chunks`
//! method](http://doc.rust-lang.org/nightly/std/slice/trait.SliceExt.html#tymethod.chunks)).
//!
//! Further, the thread pooling that does exist has a lot of
//! synchronisation overhead, and so is actually rarely a performance
//! improvement (although it is a robustness improvement over the
//! top-level functions, since it limits the number of threads that
//! will be spawned).
//!
//! Either way, **this is not recommended for general use**.
//!
//! # `simple_parallel` and stability
//!
//! This library is built around the same idea as
//! `std::thread::scoped`, and some functions suffer from [its
//! problems](https://github.com/rust-lang/rust/issues/24292). In
//! particular, there are several functions that either use `scoped`
//! directly, or expose a similar API.
//!
//! The version of this library usable with Rust 1.0 only exposes
//! `Pool`, which manually implement the same functionality as
//! `std::thread::scoped`, but do it in a way that avoids feature
//! gates. However, the `map` and `unordered_map` methods have the
//! same unsafety problem and so are marked `unsafe` (at least until
//! the standard library has a solution).
//!
//! The APIs that need the `scoped` functionality are still available
//! only nightly, with the `simple_parallel/unstable` feature.
//!
//! # Usage
//!
//! This is [available on
//! crates.io](https://crates.io/crates/simple_parallel). Add this to
//! your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! simple_parallel = "0.2"
//! ```
//!
//! The latest development version can be obtained [on
//! GitHub](https://github.com/huonw/simple_parallel).
//!
//! # Examples
//!
//! Initialise an array, in parallel.
//!
//! ```rust
//! # #[cfg(feature = "unstable")] fn foo() {
//! let mut data = [0; 10];
//! // fill the array, with one thread for each element:
//! simple_parallel::for_(data.iter_mut().enumerate(), |(i, elem)| {
//!     *elem = i as i32;
//! });
//! # }
//!
//! # let mut data = [0; 10];
//! // now adjust that data, with a threadpool:
//! let mut pool = simple_parallel::Pool::new(4);
//! pool.for_(data.iter_mut(), |elem| *elem *= 2);
//! ```
//!
//! Transform each element of an ordered map in a fancy way, in
//! parallel, with `map` (`map` ensures the output order matches the
//! input order, unlike `unordered_map`),
//!
//! ```rust
//! #[cfg(feature = "unstable")] fn foo() {
//! use std::collections::BTreeMap;
//!
//! let mut map = BTreeMap::new();
//! map.insert('a', 1);
//! map.insert('x', 55);
//!
//! let f = |(&c, &elem): (&char, _)| {
//!     let mut x = elem  * c as i32;
//!     // ... something complicated and expensive ...
//!     return x as f64
//! };
//!
//! // (`IntoIterator` is used, so "direct" iteration like this is fine.)
//! let par_iter = simple_parallel::map(&map, &f);
//!
//! // the computation is executing on several threads in the
//! // background, so that elements are hopefully ready as soon as
//! // possible.
//!
//! for value in par_iter {
//!     println!("I computed {}", value);
//! }
//! # }
//! ```
//!
//! Sum an arbitrarily long slice, in parallel, by summing subsections and adding
//! everything to a shared mutex, stored on the stack of the main
//! thread. (A parallel fold is currently missing, hence the mutex.)
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const NUM_CHUNKS: usize = 8;
//!
//! # #[cfg(feature = "unstable")]
//! fn sum(x: &[f64]) -> f64 {
//!     // (round up)
//!     let elements_per_chunk = (x.len() + NUM_CHUNKS - 1) / NUM_CHUNKS;
//!
//!     let total = Mutex::new(0.0);
//!     simple_parallel::for_(x.chunks(elements_per_chunk), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! Alternatively, one could use a thread pool, and assign an absolute
//! number of elements to each subsection and let the pool manage
//! distributing the work among threads, instead of being forced to
//! computing the length of the subsections to limit the number of
//! threads spawned.
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const ELEMS_PER_JOB: usize = 1_000;
//!
//! fn pooled_sum(pool: &mut simple_parallel::Pool, x: &[f64]) -> f64 {
//!     let total = Mutex::new(0.0);
//!     pool.for_(x.chunks(ELEMS_PER_JOB), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! A sketch of a very simple recursive parallel merge-sort, using
//! `both` to handle the recursion. (A working implementation may
//! really need some temporary buffers to mangle the data, but the key
//! point is `both` naturally running things in parallel.)
//!
//! ```rust
//! # #[cfg(feature = "unstable")] fn foo() {
//! /// Merges the two sorted runs `left` and `right`.
//! /// That is, after `merge(left, right)`,
//! ///
//! ///    left[0] <= left[1] <= ... <= left[last] <= right[0] <= ...
//! fn merge<T: Ord>(left: &mut [T], right: &mut [T]) {
//!     // magic (but non-parallel, so boring)
//! }
//!
//! fn parallel_merge_sort<T: Ord + Send>(x: &mut [T]) {
//!    // base case
//!    if x.len() <= 1 { return }
//!
//!    // get two disjoint halves of the `x`,
//!    let half = x.len() / 2;
//!    let (left, right) = x.split_at_mut(half);
//!    // and sort them recursively, in parallel
//!    simple_parallel::both(&mut *left, &mut *right, |v| parallel_merge_sort(v));
//!
//!    // now combine the two sorted halves
//!    merge(left, right)
//! }
//! # }
//! ```
//!
//! The [`examples`
//! folder](https://github.com/huonw/simple_parallel/tree/master/examples)
//! contains more intricate example(s), such as a parallel fast
//! Fourier transform implementation (it really works, and the
//! parallelism does buy something... when tuned).
#![cfg_attr(feature = "unstable", feature(scoped))]

#[cfg(feature = "unstable")]
use std::thread;
#[cfg(feature = "unstable")]
use std::iter::IntoIterator;

#[cfg(feature = "unstable")]
mod maps;

mod fnbox;

pub mod pool;

pub mod one_to_one {
    #[cfg(feature = "unstable")]
    pub use maps::{unordered_map, UnorderedParMap, map, ParMap};
}

#[cfg(feature = "unstable")]
pub use one_to_one::{map, unordered_map};

pub use pool::Pool;

/// Execute `f` on each element of `iter`, in their own `scoped`
/// thread.
///
/// If `f` panics, so does `for_`. If this occurs, the number of
/// elements of `iter` that have had `f` called on them is
/// unspecified.
#[cfg(feature = "unstable")]
pub fn for_<I: IntoIterator, F>(iter: I, ref f: F)
    where I::Item: Send, F: Fn(I::Item) + Sync
{
    let _guards: Vec<_> = iter.into_iter().map(|elem| {
        thread::scoped(move || {
            f(elem)
        })
    }).collect();
}

/// Execute `f` on both `x` and `y`, in parallel, returning the
/// result.
///
/// This is the same (including panic semantics) as `(f(x), f(y))`, up
/// to ordering. It is designed to be used for divide-and-conquer
/// algorithms.
#[cfg(feature = "unstable")]
pub fn both<T, U, F>(x: T, y: T, ref f: F) -> (U, U)
    where T: Send,
          U: Send,
          F: Sync + Fn(T) -> U
{
    let guard = thread::scoped(move || f(y));
    let a = f(x);
    let b = guard.join();
    (a, b)
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fs::File;
use std::io::{Bytes, Read};
use std::iter::Take;

fn parse_chunk<'a>(bytes: Take<Bytes<File>>) -> Result<Cow<'a, str>, std::string::FromUtf8Error> {
  String::from_utf8(bytes.map(|b| b.unwrap()).collect()).map(|s| s.into())
}

pub fn load(filename: &str) -> Result<(), &'static str> {
  let MAGIC_NUMBER = "VOX "; // om nom nom signficant whitespace

  match File::open(filename) {
    Ok(f) => {
      let iterator = f.bytes();
      match parse_chunk(iterator.take(4)) {
        Ok(magic_number) => {
          if magic_number == MAGIC_NUMBER {
            Ok(())
          } else {
            Err("Not a valid MagicaVoxel .vox file")
          }
        },
        Err(_) => Err("Unable to parse magic number chunk")
      }
    },
    Err(_) => Err("Unable to load file")
  }
}

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

    #[test]
    fn valid_file_is_read_successfully() {
        let result = load("resources/placeholder.vox");
        assert!(result.is_ok());
        //TODO test values returned
    }

    #[test]
    fn not_present_file_causes_error() {
        let result = load("resources/not_here.vox");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), "Unable to load file");
    }

    #[test]
    fn non_vox_file_causes_error() {
        let result = load("resources/not_a.vox");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), "Not a valid MagicaVoxel .vox file");
    }
}
<commit_msg>Add return type.<commit_after>use std::borrow::Cow;
use std::fs::File;
use std::io::{Bytes, Read};
use std::iter::Take;

const MAGIC_NUMBER: &'static str = "VOX "; // om nom nom signficant whitespace

#[derive(Debug, PartialEq)]
pub struct DotVoxData;

fn parse_chunk<'a>(bytes: Take<Bytes<File>>) -> Result<Cow<'a, str>, std::string::FromUtf8Error> {
  String::from_utf8(bytes.map(|b| b.unwrap()).collect()).map(|s| s.into())
}

pub fn load(filename: &str) -> Result<DotVoxData, &'static str> {
  match File::open(filename) {
    Ok(f) => {
      let iterator = f.bytes();
      match parse_chunk(iterator.take(4)) {
        Ok(magic_number) => {
          if magic_number == MAGIC_NUMBER {
            Ok(DotVoxData)
          } else {
            Err("Not a valid MagicaVoxel .vox file")
          }
        },
        Err(_) => Err("Unable to parse magic number chunk")
      }
    },
    Err(_) => Err("Unable to load file")
  }
}

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

    #[test]
    fn valid_file_is_read_successfully() {
        let result = load("resources/placeholder.vox");
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), DotVoxData);
    }

    #[test]
    fn not_present_file_causes_error() {
        let result = load("resources/not_here.vox");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), "Unable to load file");
    }

    #[test]
    fn non_vox_file_causes_error() {
        let result = load("resources/not_a.vox");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), "Not a valid MagicaVoxel .vox file");
    }
}
<|endoftext|>


<commit_before>#![feature(collections,test)]
extern crate time;

#[cfg(test)]
extern crate test;

pub mod counter;
pub mod gauge;
pub mod ewma;
pub mod meter;
pub mod metric;
pub mod registry;
<commit_msg>unneeded<commit_after>extern crate time;

pub mod counter;
pub mod gauge;
pub mod ewma;
pub mod meter;
pub mod metric;
pub mod registry;
<|endoftext|>


<commit_before>use std::vec;
use std::rc::Rc;

use sdl2::render;
use sdl2::rect::Rect;

use game::tiles::{TileSet, TileInfo};

pub struct Map {
    priv tiles: ~[u16],
    priv width_: uint,
    priv height_: uint,
    priv tileset: Rc<TileSet>
}

impl Map {
    pub fn new_test(width: uint, height: uint, tileset: Rc<TileSet>) -> Map {
        let mut map = Map {
            tiles: vec::from_elem(width * height, 0u16),
            width_: width,
            height_: height,
            tileset: tileset
        };

        for value in map.tiles.mut_iter().skip(width * (height - 2)) {
            *value = 2;
        }

        map
    }

    pub fn new_from_file(filename: ~str) -> Map {
        unimplemented!();
    }

    pub fn width(&self) -> uint {
        self.width_
    }

    pub fn height(&self) -> uint {
        self.height_
    }

    pub fn tile_size(&self) -> i32 {
        self.tileset.borrow().tile_size
    }

    pub fn tile_info_at(&self, x: uint, y: uint) -> TileInfo {
        self.tileset.borrow().id(self.get(x, y))
    }

    fn get(&self, x: uint, y: uint) -> u16 {
        assert!(x < self.width());
        assert!(y < self.height());
        self.tiles[x + y * self.width()]
    }

    pub fn draw(&self, renderer: &render::Renderer) {
        for tile_x in range(0, self.width()) {
            for tile_y in range(0, self.height()) {
                let x = tile_x * self.tile_size() as uint;
                let y = tile_y * self.tile_size() as uint;

                let dest_rect = Rect::new(x as i32, y as i32,
                        self.tile_size() as i32, self.tile_size() as i32);

                self.tileset.borrow().draw(self.get(tile_x, tile_y), dest_rect, renderer);
            }
        }
    }
}
S<commit_msg>Remove extra character at end of file<commit_after>use std::vec;
use std::rc::Rc;

use sdl2::render;
use sdl2::rect::Rect;

use game::tiles::{TileSet, TileInfo};

pub struct Map {
    priv tiles: ~[u16],
    priv width_: uint,
    priv height_: uint,
    priv tileset: Rc<TileSet>
}

impl Map {
    pub fn new_test(width: uint, height: uint, tileset: Rc<TileSet>) -> Map {
        let mut map = Map {
            tiles: vec::from_elem(width * height, 0u16),
            width_: width,
            height_: height,
            tileset: tileset
        };

        for value in map.tiles.mut_iter().skip(width * (height - 2)) {
            *value = 2;
        }

        map
    }

    pub fn new_from_file(filename: ~str) -> Map {
        unimplemented!();
    }

    pub fn width(&self) -> uint {
        self.width_
    }

    pub fn height(&self) -> uint {
        self.height_
    }

    pub fn tile_size(&self) -> i32 {
        self.tileset.borrow().tile_size
    }

    pub fn tile_info_at(&self, x: uint, y: uint) -> TileInfo {
        self.tileset.borrow().id(self.get(x, y))
    }

    fn get(&self, x: uint, y: uint) -> u16 {
        assert!(x < self.width());
        assert!(y < self.height());
        self.tiles[x + y * self.width()]
    }

    pub fn draw(&self, renderer: &render::Renderer) {
        for tile_x in range(0, self.width()) {
            for tile_y in range(0, self.height()) {
                let x = tile_x * self.tile_size() as uint;
                let y = tile_y * self.tile_size() as uint;

                let dest_rect = Rect::new(x as i32, y as i32,
                        self.tile_size() as i32, self.tile_size() as i32);

                self.tileset.borrow().draw(self.get(tile_x, tile_y), dest_rect, renderer);
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
use error::*;
use ffi::*;

#[derive(Debug, Clone)]
struct Alignment {
    in_: i32,
    out: i32,
}

impl Alignment {
    fn new<A: FFTW, B: FFTW>(in_: &[A], out: &[B]) -> Self {
        Self {
            in_: A::alignment_of(in_),
            out: B::alignment_of(out),
        }
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        if self.in_ != A::alignment_of(in_) || self.out != B::alignment_of(out) {
            Err(AlignmentMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug, Clone)]
struct Shape(Vec<i32>);

impl Shape {
    fn new(s: &[i32]) -> Self {
        Shape(s.to_vec())
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        let n = self.0.len();
        if in_.len() != n || out.len() != n {
            Err(SizeMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug)]
pub struct C2CPlan<C: FFTW> {
    plan: C::Plan,
    shape: Shape,
    sign: Sign,
    flag: FLAG,
    alignment: Alignment,
}

impl<C: FFTW<Complex = C>> C2CPlan<C> {
    pub fn new(shape: &[i32], in_: &[C], out: &[C], sign: Sign, flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2c(&shape, in_, out, sign, flag)?,
            shape: Shape::new(shape),
            sign,
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2c(&mut self, in_: &[C], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2c(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<C, R> C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[C], out: &[R], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2r(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2r(&mut self, in_: &[C], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2r(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<R, C> R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[R], out: &[C], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_r2c(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_r2c(self.plan, in_, out);
        Ok(())
    }
}

pub trait Plan: Sized {
    fn check_null(self) -> Result<Self>;
}

impl Plan for fftw_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

impl Plan for fftwf_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

/// Switch `fftw_*` and `fftwf_*`
pub trait FFTW {
    type Plan: Plan + Copy;
    type Real;
    type Complex;
    fn destroy_plan(Self::Plan);
    fn print_plan(Self::Plan);
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flags: FLAG,
    ) -> Result<Self::Plan>;
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flags: FLAG) -> Result<Self::Plan>;
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flags: FLAG) -> Result<Self::Plan>;
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Complex]);
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Real]);
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], &mut [Self::Complex]);
    fn alignment_of<T>(&[T]) -> i32;
}

macro_rules! excall {
    ($call:expr) => {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { $call }
    }
}

impl FFTW for c64 {
    type Plan = fftw_plan;
    type Real = f64;
    type Complex = c64;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftw_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftw_print_plan(p) };
    }
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flag: FLAG,
    ) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag).check_null() }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftw_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftw_alignment_of(s.as_ptr() as *mut _) }
    }
}
<commit_msg>Impl R2R<commit_after>use super::*;
use error::*;
use ffi::*;

#[derive(Debug, Clone)]
struct Alignment {
    in_: i32,
    out: i32,
}

impl Alignment {
    fn new<A: FFTW, B: FFTW>(in_: &[A], out: &[B]) -> Self {
        Self {
            in_: A::alignment_of(in_),
            out: B::alignment_of(out),
        }
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        if self.in_ != A::alignment_of(in_) || self.out != B::alignment_of(out) {
            Err(AlignmentMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug, Clone)]
struct Shape(Vec<i32>);

impl Shape {
    fn new(s: &[i32]) -> Self {
        Shape(s.to_vec())
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        let n = self.0.len();
        if in_.len() != n || out.len() != n {
            Err(SizeMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug)]
pub struct C2CPlan<C: FFTW> {
    plan: C::Plan,
    shape: Shape,
    sign: Sign,
    flag: FLAG,
    alignment: Alignment,
}

impl<C: FFTW<Complex = C>> C2CPlan<C> {
    pub fn new(shape: &[i32], in_: &[C], out: &[C], sign: Sign, flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2c(&shape, in_, out, sign, flag)?,
            shape: Shape::new(shape),
            sign,
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2c(&mut self, in_: &[C], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2c(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<C, R> C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[C], out: &[R], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2r(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2r(&mut self, in_: &[C], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2r(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<R, C> R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[R], out: &[C], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_r2c(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_r2c(self.plan, in_, out);
        Ok(())
    }
}

pub type R2RKind = ffi::fftw_r2r_kind;

#[derive(Debug)]
pub struct R2RPlan<R>
where
    R: FFTW<Real = R>,
{
    plan: R::Plan,
    shape: Shape,
    kind: Vec<R2RKind>,
    flag: FLAG,
    alignment: Alignment,
}

impl<R: FFTW<Real = R>> R2RPlan<R> {
    pub fn new(shape: &[i32], in_: &[R], out: &[R], kinds: &[R2RKind], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: R::plan_r2r(&shape, in_, out, kinds, flag)?,
            shape: Shape::new(shape),
            kind: kinds.to_vec(),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        R::exec_r2r(self.plan, in_, out);
        Ok(())
    }
}

pub trait Plan: Sized {
    fn check_null(self) -> Result<Self>;
}

impl Plan for fftw_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

impl Plan for fftwf_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

/// Switch `fftw_*` and `fftwf_*`
pub trait FFTW {
    type Plan: Plan + Copy;
    type Real;
    type Complex;
    fn destroy_plan(Self::Plan);
    fn print_plan(Self::Plan);
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flags: FLAG,
    ) -> Result<Self::Plan>;
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flags: FLAG) -> Result<Self::Plan>;
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flags: FLAG) -> Result<Self::Plan>;
    fn plan_r2r(shape: &[i32], in_: &[Self::Real], out: &[Self::Real], &[R2RKind], flags: FLAG) -> Result<Self::Plan>;
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Complex]);
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Real]);
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], &mut [Self::Complex]);
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], &mut [Self::Real]);
    fn alignment_of<T>(&[T]) -> i32;
}

macro_rules! excall {
    ($call:expr) => {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { $call }
    }
}

impl FFTW for c64 {
    type Plan = fftw_plan;
    type Real = f64;
    type Complex = c64;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftw_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftw_print_plan(p) };
    }
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flag: FLAG,
    ) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag).check_null() }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2r(
        shape: &[i32],
        in_: &[Self::Real],
        out: &[Self::Real],
        kinds: &[R2RKind],
        flag: FLAG,
    ) -> Result<Self::Plan> {
        excall!{ fftw_plan_r2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, kinds.as_ptr() as *mut _, flag).check_null() }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftw_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Real]) {
        unsafe { fftw_execute_r2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftw_alignment_of(s.as_ptr() as *mut _) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use ffi::OsString;
use marker::PhantomData;
use vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }

/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize { self.iter.len() }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "solaris",
          target_os = "emscripten",
          target_os = "haiku",
          target_os = "l4re",
          target_os = "fuchsia"))]
mod imp {
    use os::unix::prelude::*;
    use mem;
    use ffi::{CStr, OsString};
    use marker::PhantomData;
    use libc;
    use super::Args;

    use sys_common::mutex::Mutex;

    static mut GLOBAL_ARGS_PTR: usize = 0;
    static LOCK: Mutex = Mutex::new();

    pub unsafe fn init(argc: isize, argv: *const *const u8) {
        let args = (0..argc).map(|i| {
            CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
        }).collect();

        LOCK.lock();
        let ptr = get_global_ptr();
        assert!((*ptr).is_none());
        (*ptr) = Some(box args);
        LOCK.unlock();
    }

    pub unsafe fn cleanup() {
        LOCK.lock();
        *get_global_ptr() = None;
        LOCK.unlock();
    }

    pub fn args() -> Args {
        let bytes = clone().unwrap_or(Vec::new());
        let v: Vec<OsString> = bytes.into_iter().map(|v| {
            OsStringExt::from_vec(v)
        }).collect();
        Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
    }

    fn clone() -> Option<Vec<Vec<u8>>> {
        unsafe {
            LOCK.lock();
            let ptr = get_global_ptr();
            let ret = (*ptr).as_ref().map(|s| (**s).clone());
            LOCK.unlock();
            return ret
        }
    }

    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
    }

}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod imp {
    use ffi::CStr;
    use marker::PhantomData;
    use libc;
    use super::Args;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    }

    pub fn cleanup() {
    }

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use os::unix::prelude::*;
        extern {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) = (*_NSGetArgc() as isize,
                                *_NSGetArgv() as *const *const libc::c_char);
            (0.. argc as isize).map(|i| {
                let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                OsStringExt::from_vec(bytes)
            }).collect::<Vec<_>>()
        };
        Args {
            iter: vec.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use ffi::OsString;
        use mem;
        use str;

        extern {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch="aarch64")]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch="aarch64"))]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char =
                    mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
    }
}
<commit_msg>Rollup merge of #47165 - mbrubeck:args, r=alexcrichton<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use ffi::OsString;
use marker::PhantomData;
use vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }

/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize { self.iter.len() }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "solaris",
          target_os = "emscripten",
          target_os = "haiku",
          target_os = "l4re",
          target_os = "fuchsia"))]
mod imp {
    use os::unix::prelude::*;
    use ptr;
    use ffi::{CStr, OsString};
    use marker::PhantomData;
    use libc;
    use super::Args;

    use sys_common::mutex::Mutex;

    static mut ARGC: isize = 0;
    static mut ARGV: *const *const u8 = ptr::null();
    static LOCK: Mutex = Mutex::new();

    pub unsafe fn init(argc: isize, argv: *const *const u8) {
        LOCK.lock();
        ARGC = argc;
        ARGV = argv;
        LOCK.unlock();
    }

    pub unsafe fn cleanup() {
        LOCK.lock();
        ARGC = 0;
        ARGV = ptr::null();
        LOCK.unlock();
    }

    pub fn args() -> Args {
        Args {
            iter: clone().into_iter(),
            _dont_send_or_sync_me: PhantomData
        }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            LOCK.lock();
            let ret = (0..ARGC).map(|i| {
                let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
                OsStringExt::from_vec(cstr.to_bytes().to_vec())
            }).collect();
            LOCK.unlock();
            return ret
        }
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod imp {
    use ffi::CStr;
    use marker::PhantomData;
    use libc;
    use super::Args;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    }

    pub fn cleanup() {
    }

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use os::unix::prelude::*;
        extern {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) = (*_NSGetArgc() as isize,
                                *_NSGetArgv() as *const *const libc::c_char);
            (0.. argc as isize).map(|i| {
                let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                OsStringExt::from_vec(bytes)
            }).collect::<Vec<_>>()
        };
        Args {
            iter: vec.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use ffi::OsString;
        use mem;
        use str;

        extern {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch="aarch64")]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch="aarch64"))]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char =
                    mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
    }
}
<|endoftext|>


<commit_before>//! This module contains extension methods for `String` that expose
//! parallel iterators, such as `par_split_whitespace()`. You will
//! rarely need to interact with it directly, since if you add `use
//! rayon::prelude::*` to your file, that will include the helper
//! traits defined in this module.

use iter::*;
use iter::internal::*;
use split_producer::*;
use std::borrow::Borrow;

/// Test if a byte is the start of a UTF-8 character.
/// (extracted from `str::is_char_boundary`)
fn is_char_boundary(b: u8) -> bool {
    // This is bit magic equivalent to: b < 128 || b >= 192
    (b as i8) >= -0x40
}

/// Find the index of a character boundary near the midpoint.
fn find_char_midpoint(chars: &str) -> usize {
    let mid = chars.len() / 2;

    // We want to split near the midpoint, but we need to find an actual
    // character boundary.  So we look at the raw bytes, first scanning
    // forward from the midpoint for a boundary, then trying backward.
    let (left, right) = chars.as_bytes().split_at(mid);
    right.iter()
        .cloned()
        .position(is_char_boundary)
        .map(|i| mid + i)
        .or_else(|| left.iter().cloned().rposition(is_char_boundary))
        .unwrap_or(0)
}

/// Parallel extensions for strings.
pub trait ParallelString: Borrow<str> {
    /// Returns a parallel iterator over the characters of a string.
    fn par_chars(&self) -> Chars {
        Chars { chars: self.borrow() }
    }

    /// Returns a parallel iterator over substrings separated by a
    /// given character, similar to `str::split`.
    fn par_split<P: Pattern>(&self, separator: P) -> Split<P> {
        Split::new(self.borrow(), separator)
    }

    /// Returns a parallel iterator over substrings terminated by a
    /// given character, similar to `str::split_terminator`.  It's
    /// equivalent to `par_split`, except it doesn't produce an empty
    /// substring after a trailing terminator.
    fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<P> {
        SplitTerminator::new(self.borrow(), terminator)
    }

    /// Returns a parallel iterator over the lines of a string, ending with an
    /// optional carriage return and with a newline (`\r\n` or just `\n`).
    /// The final line ending is optional, and line endings are not included in
    /// the output strings.
    fn par_lines(&self) -> Lines {
        Lines(self.borrow())
    }

    /// Returns a parallel iterator over the sub-slices of a string that are
    /// separated by any amount of whitespace.
    ///
    /// As with `str::split_whitespace`, 'whitespace' is defined according to
    /// the terms of the Unicode Derived Core Property `White_Space`.
    fn par_split_whitespace(&self) -> SplitWhitespace {
        SplitWhitespace(self.borrow())
    }
}

impl<T: ?Sized + Borrow<str>> ParallelString for T {}

// /////////////////////////////////////////////////////////////////////////

/// Pattern-matching trait for `ParallelString`, somewhat like a mix of
/// `std::str::pattern::{Pattern, Searcher}`.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait Pattern: Sized + Sync {
    private_decl!{}
    fn find_in(&self, &str) -> Option<usize>;
    fn rfind_in(&self, &str) -> Option<usize>;
    fn is_suffix_of(&self, &str) -> bool;
    fn fold_with<'ch, F>(&self, &'ch str, folder: F, skip_last: bool) -> F where F: Folder<&'ch str>;
}

impl Pattern for char {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(*self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(*self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(*self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(*self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

impl<FN: Sync + Fn(char) -> bool> Pattern for FN {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over the characters of a string
pub struct Chars<'ch> {
    chars: &'ch str,
}

struct CharsProducer<'ch> {
    chars: &'ch str,
}

impl<'ch> ParallelIterator for Chars<'ch> {
    type Item = char;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge_unindexed(CharsProducer { chars: self.chars }, consumer)
    }
}

impl<'ch> UnindexedProducer for CharsProducer<'ch> {
    type Item = char;

    fn split(mut self) -> (Self, Option<Self>) {
        let index = find_char_midpoint(self.chars);
        if index > 0 {
            let (left, right) = self.chars.split_at(index);
            self.chars = left;
            (self, Some(CharsProducer { chars: right }))
        } else {
            (self, None)
        }
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume_iter(self.chars.chars())
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by a pattern
pub struct Split<'ch, P: Pattern> {
    chars: &'ch str,
    separator: P,
}

impl<'ch, P: Pattern> Split<'ch, P> {
    fn new(chars: &'ch str, separator: P) -> Self {
        Split {
            chars: chars,
            separator: separator,
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for Split<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer::new(self.chars, &self.separator);
        bridge_unindexed(producer, consumer)
    }
}

/// Implement support for `SplitProducer`.
impl<'ch, P: Pattern> Fissile<P> for &'ch str {
    fn length(&self) -> usize {
        self.len()
    }

    fn midpoint(&self, end: usize) -> usize {
        // First find a suitable UTF-8 boundary.
        find_char_midpoint(&self[..end])
    }

    fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize> {
        separator.find_in(&self[start..end])
    }

    fn rfind(&self, separator: &P, end: usize) -> Option<usize> {
        separator.rfind_in(&self[..end])
    }

    fn split_once(self, index: usize) -> (Self, Self) {
        let (left, right) = self.split_at(index);
        let mut right_iter = right.chars();
        right_iter.next(); // skip the separator
        (left, right_iter.as_str())
    }

    fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
        where F: Folder<Self>
    {
        separator.fold_with(self, folder, skip_last)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by a terminator pattern
pub struct SplitTerminator<'ch, P: Pattern> {
    chars: &'ch str,
    terminator: P,
}

struct SplitTerminatorProducer<'ch, 'sep, P: Pattern + 'sep> {
    splitter: SplitProducer<'sep, P, &'ch str>,
    skip_last: bool,
}

impl<'ch, P: Pattern> SplitTerminator<'ch, P> {
    fn new(chars: &'ch str, terminator: P) -> Self {
        SplitTerminator {
            chars: chars,
            terminator: terminator,
        }
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> SplitTerminatorProducer<'ch, 'sep, P> {
    fn new(chars: &'ch str, terminator: &'sep P) -> Self {
        SplitTerminatorProducer {
            splitter: SplitProducer::new(chars, terminator),
            skip_last: chars.is_empty() || terminator.is_suffix_of(chars),
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for SplitTerminator<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitTerminatorProducer::new(self.chars, &self.terminator);
        bridge_unindexed(producer, consumer)
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitTerminatorProducer<'ch, 'sep, P> {
    type Item = &'ch str;

    fn split(mut self) -> (Self, Option<Self>) {
        let (left, right) = self.splitter.split();
        self.splitter = left;
        let right = right.map(|right| {
            let skip_last = self.skip_last;
            self.skip_last = false;
            SplitTerminatorProducer {
                splitter: right,
                skip_last: skip_last,
            }
        });
        (self, right)
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        self.splitter.fold_with(folder, self.skip_last)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over lines in a string
pub struct Lines<'ch>(&'ch str);

impl<'ch> ParallelIterator for Lines<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split_terminator('\n')
            .map(|line| if line.ends_with('\r') {
                     &line[..line.len() - 1]
                 } else {
                     line
                 })
            .drive_unindexed(consumer)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by whitespace
pub struct SplitWhitespace<'ch>(&'ch str);

impl<'ch> ParallelIterator for SplitWhitespace<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split(char::is_whitespace)
            .filter(|string| !string.is_empty())
            .drive_unindexed(consumer)
    }
}
<commit_msg>Hide the Pattern trait and document its implementors<commit_after>//! This module contains extension methods for `String` that expose
//! parallel iterators, such as `par_split_whitespace()`. You will
//! rarely need to interact with it directly, since if you add `use
//! rayon::prelude::*` to your file, that will include the helper
//! traits defined in this module.
//!
//! Note: [`ParallelString::par_split()`] and [`par_split_terminator()`]
//! reference a `Pattern` trait which is not visible outside this crate.
//! This trait is intentionally kept private, for use only by Rayon itself.
//! It is implemented for `char` and any `F: Fn(char) -> bool + Sync`.
//!
//! [`ParallelString::par_split()`]: trait.ParallelString.html#method.par_split
//! [`par_split_terminator()`]: trait.ParallelString.html#method.par_split_terminator

use iter::*;
use iter::internal::*;
use split_producer::*;
use std::borrow::Borrow;

/// Test if a byte is the start of a UTF-8 character.
/// (extracted from `str::is_char_boundary`)
fn is_char_boundary(b: u8) -> bool {
    // This is bit magic equivalent to: b < 128 || b >= 192
    (b as i8) >= -0x40
}

/// Find the index of a character boundary near the midpoint.
fn find_char_midpoint(chars: &str) -> usize {
    let mid = chars.len() / 2;

    // We want to split near the midpoint, but we need to find an actual
    // character boundary.  So we look at the raw bytes, first scanning
    // forward from the midpoint for a boundary, then trying backward.
    let (left, right) = chars.as_bytes().split_at(mid);
    right.iter()
        .cloned()
        .position(is_char_boundary)
        .map(|i| mid + i)
        .or_else(|| left.iter().cloned().rposition(is_char_boundary))
        .unwrap_or(0)
}

/// Parallel extensions for strings.
pub trait ParallelString: Borrow<str> {
    /// Returns a parallel iterator over the characters of a string.
    fn par_chars(&self) -> Chars {
        Chars { chars: self.borrow() }
    }

    /// Returns a parallel iterator over substrings separated by a
    /// given character or predicate, similar to `str::split`.
    ///
    /// Note: the `Pattern` trait is private, for use only by Rayon itself.
    /// It is implemented for `char` and any `F: Fn(char) -> bool + Sync`.
    fn par_split<P: Pattern>(&self, separator: P) -> Split<P> {
        Split::new(self.borrow(), separator)
    }

    /// Returns a parallel iterator over substrings terminated by a
    /// given character or predicate, similar to `str::split_terminator`.
    /// It's equivalent to `par_split`, except it doesn't produce an empty
    /// substring after a trailing terminator.
    ///
    /// Note: the `Pattern` trait is private, for use only by Rayon itself.
    /// It is implemented for `char` and any `F: Fn(char) -> bool + Sync`.
    fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<P> {
        SplitTerminator::new(self.borrow(), terminator)
    }

    /// Returns a parallel iterator over the lines of a string, ending with an
    /// optional carriage return and with a newline (`\r\n` or just `\n`).
    /// The final line ending is optional, and line endings are not included in
    /// the output strings.
    fn par_lines(&self) -> Lines {
        Lines(self.borrow())
    }

    /// Returns a parallel iterator over the sub-slices of a string that are
    /// separated by any amount of whitespace.
    ///
    /// As with `str::split_whitespace`, 'whitespace' is defined according to
    /// the terms of the Unicode Derived Core Property `White_Space`.
    fn par_split_whitespace(&self) -> SplitWhitespace {
        SplitWhitespace(self.borrow())
    }
}

impl<T: ?Sized + Borrow<str>> ParallelString for T {}

// /////////////////////////////////////////////////////////////////////////

/// We hide the `Pattern` trait in a private module, as its API is not meant
/// for general consumption.  If we could have privacy on trait items, then it
/// would be nicer to have its basic existence and implementors public while
/// keeping all of the methods private.
mod private {
    use iter::internal::Folder;

    /// Pattern-matching trait for `ParallelString`, somewhat like a mix of
    /// `std::str::pattern::{Pattern, Searcher}`.
    ///
    /// Implementing this trait is not permitted outside of `rayon`.
    pub trait Pattern: Sized + Sync {
        private_decl!{}
        fn find_in(&self, &str) -> Option<usize>;
        fn rfind_in(&self, &str) -> Option<usize>;
        fn is_suffix_of(&self, &str) -> bool;
        fn fold_with<'ch, F>(&self, &'ch str, folder: F, skip_last: bool) -> F
            where F: Folder<&'ch str>;
    }
}
use self::private::Pattern;

impl Pattern for char {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(*self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(*self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(*self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(*self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

impl<FN: Sync + Fn(char) -> bool> Pattern for FN {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over the characters of a string
pub struct Chars<'ch> {
    chars: &'ch str,
}

struct CharsProducer<'ch> {
    chars: &'ch str,
}

impl<'ch> ParallelIterator for Chars<'ch> {
    type Item = char;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge_unindexed(CharsProducer { chars: self.chars }, consumer)
    }
}

impl<'ch> UnindexedProducer for CharsProducer<'ch> {
    type Item = char;

    fn split(mut self) -> (Self, Option<Self>) {
        let index = find_char_midpoint(self.chars);
        if index > 0 {
            let (left, right) = self.chars.split_at(index);
            self.chars = left;
            (self, Some(CharsProducer { chars: right }))
        } else {
            (self, None)
        }
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume_iter(self.chars.chars())
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by a pattern
pub struct Split<'ch, P: Pattern> {
    chars: &'ch str,
    separator: P,
}

impl<'ch, P: Pattern> Split<'ch, P> {
    fn new(chars: &'ch str, separator: P) -> Self {
        Split {
            chars: chars,
            separator: separator,
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for Split<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer::new(self.chars, &self.separator);
        bridge_unindexed(producer, consumer)
    }
}

/// Implement support for `SplitProducer`.
impl<'ch, P: Pattern> Fissile<P> for &'ch str {
    fn length(&self) -> usize {
        self.len()
    }

    fn midpoint(&self, end: usize) -> usize {
        // First find a suitable UTF-8 boundary.
        find_char_midpoint(&self[..end])
    }

    fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize> {
        separator.find_in(&self[start..end])
    }

    fn rfind(&self, separator: &P, end: usize) -> Option<usize> {
        separator.rfind_in(&self[..end])
    }

    fn split_once(self, index: usize) -> (Self, Self) {
        let (left, right) = self.split_at(index);
        let mut right_iter = right.chars();
        right_iter.next(); // skip the separator
        (left, right_iter.as_str())
    }

    fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
        where F: Folder<Self>
    {
        separator.fold_with(self, folder, skip_last)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by a terminator pattern
pub struct SplitTerminator<'ch, P: Pattern> {
    chars: &'ch str,
    terminator: P,
}

struct SplitTerminatorProducer<'ch, 'sep, P: Pattern + 'sep> {
    splitter: SplitProducer<'sep, P, &'ch str>,
    skip_last: bool,
}

impl<'ch, P: Pattern> SplitTerminator<'ch, P> {
    fn new(chars: &'ch str, terminator: P) -> Self {
        SplitTerminator {
            chars: chars,
            terminator: terminator,
        }
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> SplitTerminatorProducer<'ch, 'sep, P> {
    fn new(chars: &'ch str, terminator: &'sep P) -> Self {
        SplitTerminatorProducer {
            splitter: SplitProducer::new(chars, terminator),
            skip_last: chars.is_empty() || terminator.is_suffix_of(chars),
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for SplitTerminator<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitTerminatorProducer::new(self.chars, &self.terminator);
        bridge_unindexed(producer, consumer)
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitTerminatorProducer<'ch, 'sep, P> {
    type Item = &'ch str;

    fn split(mut self) -> (Self, Option<Self>) {
        let (left, right) = self.splitter.split();
        self.splitter = left;
        let right = right.map(|right| {
            let skip_last = self.skip_last;
            self.skip_last = false;
            SplitTerminatorProducer {
                splitter: right,
                skip_last: skip_last,
            }
        });
        (self, right)
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        self.splitter.fold_with(folder, self.skip_last)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over lines in a string
pub struct Lines<'ch>(&'ch str);

impl<'ch> ParallelIterator for Lines<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split_terminator('\n')
            .map(|line| if line.ends_with('\r') {
                     &line[..line.len() - 1]
                 } else {
                     line
                 })
            .drive_unindexed(consumer)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by whitespace
pub struct SplitWhitespace<'ch>(&'ch str);

impl<'ch> ParallelIterator for SplitWhitespace<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split(char::is_whitespace)
            .filter(|string| !string.is_empty())
            .drive_unindexed(consumer)
    }
}
<|endoftext|>