<commit_before>extern crate taglib;

use std::env;

pub fn main() {
  let args: Vec<String> = env::args().collect();

  for arg in &args {
    let file =
      match taglib::File::new(arg) {
        Ok(f) => f,
        Err(e) => {
          println!("Invalid file {} (error: {:?})", arg, e);
          continue;
        }
      };

    println!("*** \"{}\" ***", arg);

    match file.tag() {
      Ok(t) => {
        println!("-- TAG --");
        println!("title   - {}", t.title());
        println!("artist  - {}", t.artist());
        println!("album   - {}", t.album());
        println!("year    - {}", t.year());
        println!("comment - {}", t.comment());
        println!("track   - {}", t.track());
        println!("genre   - {}", t.genre());
      },
      Err(e) => {
        println!("No available tags for {} (error: {:?})", arg, e);
      }
    }

    match file.audioproperties() {
      Ok(p) => {
        let secs = p.length() % 60;
        let mins = (p.length() - secs) / 60;

        println!("-- AUDIO --");
        println!("bitrate     - {}", p.bitrate());
        println!("sample rate - {}", p.samplerate());
        println!("channels    - {}", p.channels());
        println!("length      - {}m:{}s", mins, secs);
      },
      Err(e) => {
        println!("No available audio properties for {} (error: {:?})", arg, e);
      }
    }
  }
}
<commit_msg>examples: Skip argv[0]<commit_after>extern crate taglib;

use std::env;

pub fn main() {
  let args: Vec<String> = env::args().collect();

  for i in 1..args.len() {
    let ref arg = args[i];
    let file =
      match taglib::File::new(arg) {
        Ok(f) => f,
        Err(e) => {
          println!("Invalid file {} (error: {:?})", arg, e);
          continue;
        }
      };

    println!("*** \"{}\" ***", arg);

    match file.tag() {
      Ok(t) => {
        println!("-- TAG --");
        println!("title   - {}", t.title());
        println!("artist  - {}", t.artist());
        println!("album   - {}", t.album());
        println!("year    - {}", t.year());
        println!("comment - {}", t.comment());
        println!("track   - {}", t.track());
        println!("genre   - {}", t.genre());
      },
      Err(e) => {
        println!("No available tags for {} (error: {:?})", arg, e);
      }
    }

    match file.audioproperties() {
      Ok(p) => {
        let secs = p.length() % 60;
        let mins = (p.length() - secs) / 60;

        println!("-- AUDIO --");
        println!("bitrate     - {}", p.bitrate());
        println!("sample rate - {}", p.samplerate());
        println!("channels    - {}", p.channels());
        println!("length      - {}m:{}s", mins, secs);
      },
      Err(e) => {
        println!("No available audio properties for {} (error: {:?})", arg, e);
      }
    }
  }
}
<|endoftext|>


<commit_before>
// Use this syntax to import more than one type from the same root type
use std::io::{self, Write};

fn fib(n: usize) -> usize {
    // Compared to C++, in Rust parenthesis around the expression for if/else
    // statements are not necessary. You can use them but the compiler will
    // warn you that they are unnecessary
    if n == 0 {
        // Numeric literals in Rust can be postfixed with the exact name of the
        // available numeric types, e.g. 1u32 or 2i64
        return 0usize;
    }
    else if n == 1 {
        // Returning values in Rust is also done by writing an expression
        // rather than
        // a statement. I.e. you can omit the trailing ";" at the end of the
        // expression, e.g.:
        //
        //   1usize
        //
        return 1usize;
    }
    else {
        return fib(n-1usize) + fib(n-2usize);
    }
}

fn main() {
    // "print!" is like "println!" which is used in most examples in the rust
    // book but it doesn't output a newline
    print!("Enter what Fibonacci number you want to compute: ");
    // We need to flush the buffer because print!() does not output a newline
    // character and does not flush; it uses STDOUT which is buffered
    io::stdout().flush().unwrap();

    // ::new() is an associated function implemented on a type, in this case on
    // type String, rather than an instance of String. They are basically
    // equivalent to C++'s static methods
    //
    // Making the variable "mut" (mutable) allows us to change it. In Rust
    // variables are constant (unmutable) by default
    let mut n = String::new();

    // stdin() returns an instance of std::io::Stdin, which represents a handle
    // to the STD output. Equivalent to C++'s std::cin
    //
    // .read_line() is used to read until a newline character is found
    //
    // .expect() checks the return type of .read_line(), which is an enum, and
    // uses the match control operator to check whether the function returned
    // an error enum variant or a success enum variant. On success, it returns
    // the value which the function returns upon success, whereas upon failure
    // it will panic and exit the program after printing the message we pased to
    // it.
    //
    // See enums in the Rust book and std::result, std::result::Result for more
    // information
    io::stdin().read_line(&mut n).expect("Failed to read from STDIN!");

    // In Rust we can perform variable "shadowing". Here the previous
    // declaration of "n" was of type String but now we declare a new variable
    // with name "n" but of numerical type, which is obtained by running the
    // .parse() method. When referring to "n" we will use the latest instance
    // of a type named "n" and not the String instance anymore.
    //
    // .parse() uses the trait FromStr to determine whether
    // a type supports this operation (converting to something from a String)
    let n: usize = n.trim().parse().expect("Invalid input!");

    println!("The computed value is: {}", fib(n));
}
<commit_msg>Idiomatic changes, dynamicprogrmaming version<commit_after>
// Use this syntax to import more than one type from the same root type
use std::io::{self, Write};

fn fib_recursive(n: u64) -> u64 {
    // Compared to C++, in Rust parenthesis around the expression for if/else
    // statements are not necessary. You can use them but the compiler will
    // warn you that they are unnecessary
    if n == 0 {
        // Numeric literals in Rust can be postfixed with the exact name of the
        // available numeric types, e.g. 1u32 or 2i64, you can also write 1_u32, etc
        // However, this isn't necessary most of the time, the rust compiler is able
        // to infer the type.
        0
    } else if n == 1 {
        // Most things in Rust are expressions, this if/else/else statement is
        // an expression, and we can tell Rust to return it, rather than writing
        // return 1; here, above, and below.
        1
    } else {
        fib_recursive(n - 1) + fib_recursive(n - 2)
    }
}

// A dynamic programming version of fib
fn fib_dp(n: u64) -> u64 {
    if n == 0 || n == 1 {
        n
    } else {
        let mut f1 = 0;
        let mut f2 = 1;
        let mut total = 0;

        // The underscore here tells Rust to throw away the value, I'm not going to use it.
        // On the right half of the 'in', I'm writing a range expression. If you're familiar
        // with python it's like range(2,n+1). The format of x..y is 'half-open', where
        // x is inclusive and y is exclusive
        for _ in 2..(n + 1) {
            total = f1 + f2;
            f1 = f2;
            f2 = total;
        }
        // again, here, we could have written return total; but it's often
        // more concise and idiomatic Rust to just write the value
        total
    }
}

fn main() {
    // "print!" is like "println!" which is used in most examples in the rust
    // book but it doesn't output a newline
    print!("Enter what Fibonacci number you want to compute: ");
    // We need to flush the buffer because print!() does not output a newline
    // character and does not flush; it uses STDOUT which is buffered
    io::stdout().flush().unwrap();

    // ::new() is an associated function implemented on a type, in this case on
    // type String, rather than an instance of String. They are basically
    // equivalent to C++'s static methods
    //
    // Making the variable "mut" (mutable) allows us to change it. In Rust
    // variables are constant (unmutable) by default
    let mut n = String::new();

    // stdin() returns an instance of std::io::Stdin, which represents a handle
    // to the STD output. Equivalent to C++'s std::cin
    //
    // .read_line() is used to read until a newline character is found
    //
    // .expect() checks the return type of .read_line(), which is an enum, and
    // uses the match control operator to check whether the function returned
    // an error enum variant or a success enum variant. On success, it returns
    // the value which the function returns upon success, whereas upon failure
    // it will panic and exit the program after printing the message we pased to
    // it.
    //
    // See enums in the Rust book and std::result, std::result::Result for more
    // information
    io::stdin()
        .read_line(&mut n)
        .expect("Failed to read from STDIN!");

    // In Rust we can perform variable "shadowing". Here the previous
    // declaration of "n" was of type String but now we declare a new variable
    // with name "n" but of numerical type, which is obtained by running the
    // .parse() method. When referring to "n" we will use the latest instance
    // of a type named "n" and not the String instance anymore.
    //
    // .parse() uses the trait FromStr to determine whether
    // a type supports this operation (converting to something from a String)
    let n: u64 = n.trim().parse().expect("Invalid input!");

    println!("The computed value is: {}", fib_recursive(n));
    println!("The computed value is: {}", fib_dp(n));
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "coinaddress"]

//! Functions for validating the base58 hash checksums, including specifically
//! the bitcoin and litecoin addresses.

extern crate num;
extern crate rustc;
extern crate test;

use num::bigint::BigUint;
use num::Zero;
use std::num::{from_uint, from_int, ToPrimitive};
use rustc::util::sha2::{Sha256, Digest};

#[derive(PartialEq, Show, Copy)]
pub enum ValidationError {
    /// Given address is too short to be valid
    TooShort,
    /// Encoding is not a valid base58
    InvalidEncoding,
    /// Computed hash does not match the embedded one
    HashMismatch,

    // currency specific
    /// This address is not a bitcoin address (testnet or real).
    /// May happen when attempting to validate btc address
    NotBitcoin,
    /// This address is not a litecoin address.
    /// May happen when attempting to validate ltc address
    NotLitecoin,
}

static BASE58_CHARS: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

fn decode_base58(bc: &str) -> Option<BigUint> {
    let mut res: BigUint = Zero::zero();
    let b58: BigUint = from_int(58).unwrap();

    for c in bc.chars() {
        match BASE58_CHARS.find(c) {
            None => {
                return None
            },
            Some(x) => {
                res = res * &b58 + from_uint::<BigUint>(x).unwrap();
            }
        }
    }
    Some(res)
}

fn bigint_to_bytes(n: BigUint) -> Vec<u8> {
    let mut res: Vec<u8> = Vec::new();
    let mut tmp = n;
    let b256: BigUint = from_int(256).unwrap();

    while !tmp.is_zero() {
        res.insert(0, (&tmp % &b256).to_u8().unwrap());
        tmp = tmp / &b256;
    }

    if res.len() == 0 {
        return vec!(0);
    }

    res
}

fn pad_to(v: Vec<u8>, len: usize) -> Vec<u8> {
    let mut tmp: Vec<u8> = v;
    while tmp.len() < len {
        tmp.insert(0, 0)
    }
    tmp
}

fn double_sha256(chunk: &[u8]) -> Vec<u8> {
    let mut hash = Sha256::new();
    hash.input(chunk);
    let mut hash2 = Sha256::new();
    hash2.input(hash.result_bytes().as_slice());
    hash2.result_bytes()
}

/// Validate provided generic base58 hash.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_base58_hash(addr: &str) -> Result<usize, ValidationError> {
    if addr.len() == 0 {
        return Err(ValidationError::TooShort);
    }

    let big = match decode_base58(addr) {
        None => return Err(ValidationError::InvalidEncoding),
        Some(x) => x
    };
    let bytes = bigint_to_bytes(big);
    let padded = pad_to(bytes, 25);

    let hash = double_sha256(padded.slice(0, padded.len() - 4));
    let short_hash = hash.slice(0, 4);
    let known = padded.slice(padded.len()-4, padded.len());
    if short_hash.as_slice() == known {
        Ok(padded[0] as usize)
    } else {
        Err(ValidationError::HashMismatch)
    }
}

/// Validate bitcoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_btc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(0) => Ok(0),      // real address
        Ok(5) => Ok(5),      // script hash
        Ok(111) => Ok(111),  // testnet address
        Ok(_) => Err(ValidationError::NotBitcoin),
        Err(x) => Err(x)
    }
}

/// Validate litecoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_ltc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(48) => Ok(48),      // real address
        Ok(111) => Ok(111),    // testnet address
        Ok(_) => Err(ValidationError::NotLitecoin),
        Err(x) => Err(x)
    }
}

#[test]
fn test_decoding() {
    use std::num::from_str_radix;

    assert_eq!(decode_base58("1"), from_int(0));
    assert_eq!(decode_base58("1AaZz"), from_int(0x1C8485));
    assert_eq!(decode_base58("AO"), None);
    assert_eq!(decode_base58("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), from_str_radix("65A16059864A2FDBC7C99A4723A8395BC6F188EBC046B2FF", 16));
}

#[test]
fn test_to_bytes() {
    assert_eq!(bigint_to_bytes(Zero::zero()), vec!(0));
    assert_eq!(bigint_to_bytes(from_int(1).unwrap()), vec!(1));
    assert_eq!(bigint_to_bytes(from_int(256).unwrap()), vec!(1, 0));
}

#[test]
fn test_validate_hash() {
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_base58_hash("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYheX"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYh  "), Err(ValidationError::InvalidEncoding));
    assert_eq!(validate_base58_hash("1"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash(""), Err(ValidationError::TooShort));
}

#[test]
fn test_validate_btc_address() {
    assert_eq!(validate_btc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_btc_address("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX"), Ok(5));
    assert_eq!(validate_btc_address("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_btc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Err(ValidationError::NotBitcoin));
}

#[test]
fn test_validate_ltc_address() {
    assert_eq!(validate_ltc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Ok(48));
    assert_eq!(validate_ltc_address("muen9zszN6rVwXaFw48xh6YkdUSjJcfzek"), Ok(111));
    assert_eq!(validate_ltc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Err(ValidationError::NotLitecoin));
}

#[bench]
fn bench_validate_hash(b: &mut test::Bencher) {
    b.iter(|| {
        validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem")
    })
}
<commit_msg>Fix from_str_radix from new rust<commit_after>#![crate_type = "lib"]
#![crate_name = "coinaddress"]

//! Functions for validating the base58 hash checksums, including specifically
//! the bitcoin and litecoin addresses.

extern crate num;
extern crate rustc;
extern crate test;

use num::bigint::BigUint;
use num::Zero;
use std::num::{from_uint, from_int, ToPrimitive};
use rustc::util::sha2::{Sha256, Digest};

#[derive(PartialEq, Show, Copy)]
pub enum ValidationError {
    /// Given address is too short to be valid
    TooShort,
    /// Encoding is not a valid base58
    InvalidEncoding,
    /// Computed hash does not match the embedded one
    HashMismatch,

    // currency specific
    /// This address is not a bitcoin address (testnet or real).
    /// May happen when attempting to validate btc address
    NotBitcoin,
    /// This address is not a litecoin address.
    /// May happen when attempting to validate ltc address
    NotLitecoin,
}

static BASE58_CHARS: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

fn decode_base58(bc: &str) -> Option<BigUint> {
    let mut res: BigUint = Zero::zero();
    let b58: BigUint = from_int(58).unwrap();

    for c in bc.chars() {
        match BASE58_CHARS.find(c) {
            None => {
                return None
            },
            Some(x) => {
                res = res * &b58 + from_uint::<BigUint>(x).unwrap();
            }
        }
    }
    Some(res)
}

fn bigint_to_bytes(n: BigUint) -> Vec<u8> {
    let mut res: Vec<u8> = Vec::new();
    let mut tmp = n;
    let b256: BigUint = from_int(256).unwrap();

    while !tmp.is_zero() {
        res.insert(0, (&tmp % &b256).to_u8().unwrap());
        tmp = tmp / &b256;
    }

    if res.len() == 0 {
        return vec!(0);
    }

    res
}

fn pad_to(v: Vec<u8>, len: usize) -> Vec<u8> {
    let mut tmp: Vec<u8> = v;
    while tmp.len() < len {
        tmp.insert(0, 0)
    }
    tmp
}

fn double_sha256(chunk: &[u8]) -> Vec<u8> {
    let mut hash = Sha256::new();
    hash.input(chunk);
    let mut hash2 = Sha256::new();
    hash2.input(hash.result_bytes().as_slice());
    hash2.result_bytes()
}

/// Validate provided generic base58 hash.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_base58_hash(addr: &str) -> Result<usize, ValidationError> {
    if addr.len() == 0 {
        return Err(ValidationError::TooShort);
    }

    let big = match decode_base58(addr) {
        None => return Err(ValidationError::InvalidEncoding),
        Some(x) => x
    };
    let bytes = bigint_to_bytes(big);
    let padded = pad_to(bytes, 25);

    let hash = double_sha256(padded.slice(0, padded.len() - 4));
    let short_hash = hash.slice(0, 4);
    let known = padded.slice(padded.len()-4, padded.len());
    if short_hash.as_slice() == known {
        Ok(padded[0] as usize)
    } else {
        Err(ValidationError::HashMismatch)
    }
}

/// Validate bitcoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_btc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(0) => Ok(0),      // real address
        Ok(5) => Ok(5),      // script hash
        Ok(111) => Ok(111),  // testnet address
        Ok(_) => Err(ValidationError::NotBitcoin),
        Err(x) => Err(x)
    }
}

/// Validate litecoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_ltc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(48) => Ok(48),      // real address
        Ok(111) => Ok(111),    // testnet address
        Ok(_) => Err(ValidationError::NotLitecoin),
        Err(x) => Err(x)
    }
}

#[test]
fn test_decoding() {
    use std::num::from_str_radix;

    assert_eq!(decode_base58("1"), from_int(0));
    assert_eq!(decode_base58("1AaZz"), from_int(0x1C8485));
    assert_eq!(decode_base58("AO"), None);
    assert_eq!(decode_base58("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), from_str_radix("65A16059864A2FDBC7C99A4723A8395BC6F188EBC046B2FF", 16).ok());
}

#[test]
fn test_to_bytes() {
    assert_eq!(bigint_to_bytes(Zero::zero()), vec!(0));
    assert_eq!(bigint_to_bytes(from_int(1).unwrap()), vec!(1));
    assert_eq!(bigint_to_bytes(from_int(256).unwrap()), vec!(1, 0));
}

#[test]
fn test_validate_hash() {
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_base58_hash("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYheX"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYh  "), Err(ValidationError::InvalidEncoding));
    assert_eq!(validate_base58_hash("1"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash(""), Err(ValidationError::TooShort));
}

#[test]
fn test_validate_btc_address() {
    assert_eq!(validate_btc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_btc_address("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX"), Ok(5));
    assert_eq!(validate_btc_address("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_btc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Err(ValidationError::NotBitcoin));
}

#[test]
fn test_validate_ltc_address() {
    assert_eq!(validate_ltc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Ok(48));
    assert_eq!(validate_ltc_address("muen9zszN6rVwXaFw48xh6YkdUSjJcfzek"), Ok(111));
    assert_eq!(validate_ltc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Err(ValidationError::NotLitecoin));
}

#[bench]
fn bench_validate_hash(b: &mut test::Bencher) {
    b.iter(|| {
        validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem")
    })
}
<|endoftext|>


<commit_before>use {Bytes, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, Bytes)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    match http_client.get_http_response_using_headers(url, http_header) {
        Ok(mut body) => {
            // TODO This condition must return an error here, breaking the other threads
            if !body.check_partialcontent_status() {
                return Ok(0u64);
            }
            let mut bytes_buffer = [0; 2048];
            let mut sum_bytes = 0;
            while let Ok(n) = body.read(&mut bytes_buffer) {
                if n == 0 {
                    return Ok(sum_bytes);
                }
                chunk_vector.extend_from_slice(&bytes_buffer[..n]);
                sum_bytes += n as u64;
                mpb.add(n as u64);
            }
            return Ok(0u64);
        }
        Err(http_error) => Err(http_error),
    }

}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        let mut mp = mpb.create_bar(chunk_length);
        mp.message(&format!("Chunk {} - ", chunk_index));

        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                                    http_header,
                                                                    &mut chunk_content,
                                                                    &url_clone,
                                                                    &mut mp) {
            Ok(bytes_written) => {
                if bytes_written > 0 {
                    let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                    shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    mp.finish();
                } else {
                    panic!("The downloaded chunk {} is empty", chunk_index);
                }
            }
            Err(error) => {
                panic!("Canno't download the chunk {}, due to error {}",
                       chunk_index,
                       error);
            }
        }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}
<commit_msg>Format code when downloading chunks<commit_after>use {Bytes, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, Bytes)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; 2048];
    let mut sum_bytes = 0;
    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }
        chunk_vector.extend_from_slice(&bytes_buffer[..n]);
        sum_bytes += n as u64;
        mpb.add(n as u64);
    }
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        let mut mp = mpb.create_bar(chunk_length);
        mp.message(&format!("Chunk {} - ", chunk_index));

        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                                    http_header,
                                                                    &mut chunk_content,
                                                                    &url_clone,
                                                                    &mut mp) {
            Ok(bytes_written) => {
                if bytes_written > 0 {
                    let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                    shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    mp.finish();
                } else {
                    panic!("The downloaded chunk {} is empty", chunk_index);
                }
            }
            Err(error) => {
                panic!("Canno't download the chunk {}, due to error {}",
                       chunk_index,
                       error);
            }
        }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}
<|endoftext|>


<commit_before>#![feature(test)]
#[cfg(test)]

extern crate congalife;
extern crate test;

use congalife::Game;
use test::Bencher;

#[bench]
fn bench_advance_game_64(b: &mut Bencher) {
	let game: Game = Game::new(64, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_128(b: &mut Bencher) {
    let game: Game = Game::new(128, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_512(b: &mut Bencher) {
    let game: Game = Game::new(512, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_toroidally_64(b: &mut Bencher) {
	let game: Game = Game::new(64, 0.2);
    b.iter(|| game.advance_toroidally());
}

#[bench]
fn bench_advance_game_toroidally_128(b: &mut Bencher) {
    let game: Game = Game::new(128, 0.2);
    b.iter(|| game.advance_toroidally());
}

#[bench]
fn bench_advance_game_toroidally_512(b: &mut Bencher) {
    let game: Game = Game::new(512, 0.2);
    b.iter(|| game.advance_toroidally());
}
<commit_msg>Add some larger advancing benchmarks<commit_after>#![feature(test)]
#[cfg(test)]

extern crate congalife;
extern crate test;

use congalife::Game;
use test::Bencher;

#[bench]
fn bench_advance_game_64(b: &mut Bencher) {
	let game: Game = Game::new(64, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_128(b: &mut Bencher) {
    let game: Game = Game::new(128, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_512(b: &mut Bencher) {
    let game: Game = Game::new(512, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_1024(b: &mut Bencher) {
    let game: Game = Game::new(1024, 0.2);
    b.iter(|| game.advance());
}

#[bench]
fn bench_advance_game_2048(b: &mut Bencher) {
    let game: Game = Game::new(2048, 0.2);
    b.iter(|| game.advance());
}

// #[bench]
// fn bench_advance_game_toroidally_64(b: &mut Bencher) {
// 	let game: Game = Game::new(64, 0.2);
//     b.iter(|| game.advance_toroidally());
// }

// #[bench]
// fn bench_advance_game_toroidally_128(b: &mut Bencher) {
//     let game: Game = Game::new(128, 0.2);
//     b.iter(|| game.advance_toroidally());
// }

// #[bench]
// fn bench_advance_game_toroidally_512(b: &mut Bencher) {
//     let game: Game = Game::new(512, 0.2);
//     b.iter(|| game.advance_toroidally());
// }
<|endoftext|>


<commit_before>extern crate libc;

use array::Array;
use defines::AfError;
use defines::MatProp;
use error::HANDLE_ERROR;
use self::libc::{c_uint, c_int};
use util::{AfArray, MutAfArray, to_u32};

#[allow(dead_code)]
extern {
    fn af_matmul(out: MutAfArray, lhs: AfArray, rhs: AfArray,
                 optlhs: c_uint, optrhs: c_uint) -> c_int;

    fn af_dot(out: MutAfArray, lhs: AfArray, rhs: AfArray,
              optlhs: c_uint, optrhs: c_uint) -> c_int;

    fn af_transpose(out: MutAfArray, arr: AfArray, conjugate: c_int) -> c_int;
    fn af_transpose_inplace(arr: AfArray, conjugate: c_int) -> c_int;
}

/// Matrix multiple of two Arrays
///
/// # Parameters
///
/// - `lhs` is the Array on left hand side
/// - `rhs` is the Array on right hand side
/// - `optlhs` - Transpose left hand side before the function is performed, uses one of the values of [MatProp](./enum.MatProp.html)
/// - `optrhs` - Transpose right hand side before the function is performed, uses one of the values of [MatProp](./enum.MatProp.html)
///
/// # Return Values
///
/// The result Array of matrix multiplication
#[allow(unused_mut)]
pub fn matmul(lhs: &Array, rhs: &Array,
              optlhs: MatProp, optrhs: MatProp) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_matmul(&mut temp as MutAfArray,
                                lhs.get() as AfArray, rhs.get() as AfArray,
                                to_u32(optlhs) as c_uint, to_u32(optrhs) as c_uint);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Calculate the dot product of vectors.
///
/// Scalar dot product between two vectors. Also referred to as the inner product. This function returns the scalar product of two equal sized vectors or between a matrix and a vector. The second operand needs to be a vector in either case.
///
/// # Parameters
///
/// - `lhs` - Left hand side of dot operation
/// - `rhs` - Right hand side of dot operation
/// - `optlhs` - Options for lhs. Currently only NONE value from [MatProp](./enum.MatProp.html) is supported.
/// - `optrhs` - Options for rhs. Currently only NONE value from [MatProp](./enum.MatProp.html) is supported.
///
/// # Return Values
///
/// The result of dot product.
#[allow(unused_mut)]
pub fn dot(lhs: &Array, rhs: &Array,
           optlhs: MatProp, optrhs: MatProp) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_dot(&mut temp as MutAfArray,
                             lhs.get() as AfArray, rhs.get() as AfArray,
                             to_u32(optlhs) as c_uint, to_u32(optrhs) as c_uint);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Transpose of a matrix.
///
/// # Parameters
///
/// - `arr` is the input Array
/// - `conjugate` is a boolean that indicates if the transpose operation needs to be a conjugate
/// transpose
///
/// # Return Values
///
/// Transposed Array.
#[allow(unused_mut)]
pub fn transpose(arr: &Array, conjugate: bool) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_transpose(&mut temp as MutAfArray,
                                   arr.get() as AfArray, conjugate as c_int);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Inplace transpose of a matrix.
///
/// # Parameters
///
/// - `arr` is the input Array that has to be transposed
/// - `conjugate` is a boolean that indicates if the transpose operation needs to be a conjugate
/// transpose
#[allow(unused_mut)]
pub fn transpose_inplace(arr: &mut Array, conjugate: bool) {
    unsafe {
        let err_val = af_transpose_inplace(arr.get() as AfArray, conjugate as c_int);
        HANDLE_ERROR(AfError::from(err_val));
    }
}
<commit_msg>Correct documentation mistake in dot function<commit_after>extern crate libc;

use array::Array;
use defines::AfError;
use defines::MatProp;
use error::HANDLE_ERROR;
use self::libc::{c_uint, c_int};
use util::{AfArray, MutAfArray, to_u32};

#[allow(dead_code)]
extern {
    fn af_matmul(out: MutAfArray, lhs: AfArray, rhs: AfArray,
                 optlhs: c_uint, optrhs: c_uint) -> c_int;

    fn af_dot(out: MutAfArray, lhs: AfArray, rhs: AfArray,
              optlhs: c_uint, optrhs: c_uint) -> c_int;

    fn af_transpose(out: MutAfArray, arr: AfArray, conjugate: c_int) -> c_int;
    fn af_transpose_inplace(arr: AfArray, conjugate: c_int) -> c_int;
}

/// Matrix multiple of two Arrays
///
/// # Parameters
///
/// - `lhs` is the Array on left hand side
/// - `rhs` is the Array on right hand side
/// - `optlhs` - Transpose left hand side before the function is performed, uses one of the values of [MatProp](./enum.MatProp.html)
/// - `optrhs` - Transpose right hand side before the function is performed, uses one of the values of [MatProp](./enum.MatProp.html)
///
/// # Return Values
///
/// The result Array of matrix multiplication
#[allow(unused_mut)]
pub fn matmul(lhs: &Array, rhs: &Array,
              optlhs: MatProp, optrhs: MatProp) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_matmul(&mut temp as MutAfArray,
                                lhs.get() as AfArray, rhs.get() as AfArray,
                                to_u32(optlhs) as c_uint, to_u32(optrhs) as c_uint);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Calculate the dot product of vectors.
///
/// Scalar dot product between two vectors. Also referred to as the inner product. This function returns the scalar product of two equal sized vectors.
///
/// # Parameters
///
/// - `lhs` - Left hand side of dot operation
/// - `rhs` - Right hand side of dot operation
/// - `optlhs` - Options for lhs. Currently only NONE value from [MatProp](./enum.MatProp.html) is supported.
/// - `optrhs` - Options for rhs. Currently only NONE value from [MatProp](./enum.MatProp.html) is supported.
///
/// # Return Values
///
/// The result of dot product.
#[allow(unused_mut)]
pub fn dot(lhs: &Array, rhs: &Array,
           optlhs: MatProp, optrhs: MatProp) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_dot(&mut temp as MutAfArray,
                             lhs.get() as AfArray, rhs.get() as AfArray,
                             to_u32(optlhs) as c_uint, to_u32(optrhs) as c_uint);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Transpose of a matrix.
///
/// # Parameters
///
/// - `arr` is the input Array
/// - `conjugate` is a boolean that indicates if the transpose operation needs to be a conjugate
/// transpose
///
/// # Return Values
///
/// Transposed Array.
#[allow(unused_mut)]
pub fn transpose(arr: &Array, conjugate: bool) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_transpose(&mut temp as MutAfArray,
                                   arr.get() as AfArray, conjugate as c_int);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Inplace transpose of a matrix.
///
/// # Parameters
///
/// - `arr` is the input Array that has to be transposed
/// - `conjugate` is a boolean that indicates if the transpose operation needs to be a conjugate
/// transpose
#[allow(unused_mut)]
pub fn transpose_inplace(arr: &mut Array, conjugate: bool) {
    unsafe {
        let err_val = af_transpose_inplace(arr.get() as AfArray, conjugate as c_int);
        HANDLE_ERROR(AfError::from(err_val));
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;
extern crate walkdir;

use clap::{App, Arg};
use regex::Regex;
use std::borrow::Borrow;
use std::fs;
use std::io;
use std::path::Path;
use walkdir::{DirEntry, WalkDir};

fn main() {
    let matches = App::new("mvb")
        .author("Peter Teixeira")
        .about("Bulk renames files")
        .arg(Arg::with_name("from_pattern").required(true).index(1))
        .arg(Arg::with_name("to_pattern").required(true).index(2))
        .arg(
            Arg::with_name("preserve")
                .required(false)
                .short("p")
                .long("preserve")
                .help("Preserve original files (make copies at new location)"),
        )
        .get_matches();

    let from_pattern = matches.value_of("from_pattern").unwrap();
    let to_pattern = matches.value_of("to_pattern").unwrap();
    let backup = matches.is_present("preserve");
    let re = Regex::new(from_pattern).expect("Could not parse input pattern");

    for entry in WalkDir::new(".").into_iter().filter_map(|e| e.ok()) {
        if backup {
            try_copy_file(entry, &to_pattern, &re);
        } else {
            try_move_file(entry, &to_pattern, &re);
        }
    }
}

fn try_move_file(entry: DirEntry, target_pattern: &str, re: &Regex) -> Option<io::Result<()>> {
    let filename = entry.file_name().to_str()?;

    if !re.is_match(filename) {
        return None;
    }

    let replaced_name = re.replace(filename, target_pattern);
    let target_file_name: &str = replaced_name.borrow();
    let target_file_path = Path::new(target_file_name);

    Some(fs::rename(entry.path(), target_file_path))
}

fn try_copy_file(entry: DirEntry, target_pattern: &str, re: &Regex) -> Option<io::Result<()>> {
    let filename = entry.file_name().to_str()?;

    if !re.is_match(filename) {
        return None;
    }

    let replaced_name = re.replace(filename, target_pattern);
    let target_file_name: &str = replaced_name.borrow();
    let target_file_path = Path::new(target_file_name);

    return match fs::copy(entry.path(), target_file_path) {
        Ok(_) => Some(Ok(())),
        Err(e) => Some(Err(e))
    }
}
<commit_msg>Actually signal errors<commit_after>extern crate clap;
extern crate regex;
extern crate walkdir;

use clap::{App, Arg};
use regex::Regex;
use std::borrow::Borrow;
use std::fs;
use std::io;
use std::path::Path;
use walkdir::{DirEntry, WalkDir};

fn main() {
    let result = run_app();

    if !result {
        std::process::exit(1);
    }
}

fn run_app() -> bool {
    let matches = App::new("mvb")
        .author("Peter Teixeira")
        .about("Bulk renames files")
        .arg(Arg::with_name("from_pattern").required(true).index(1))
        .arg(Arg::with_name("to_pattern").required(true).index(2))
        .arg(
            Arg::with_name("preserve")
                .required(false)
                .short("p")
                .long("preserve")
                .help("Preserve original files (make copies at new location)"),
        )
        .get_matches();

    let from_pattern = matches.value_of("from_pattern").unwrap();
    let to_pattern = matches.value_of("to_pattern").unwrap();
    let backup = matches.is_present("preserve");
    let re = Regex::new(from_pattern).expect("Could not parse input pattern");

    let mut exit_ok = true;
    for entry in WalkDir::new(".").into_iter().filter_map(|e| e.ok()) {
        let move_result = if backup {
            try_copy_file(entry, &to_pattern, &re)
        } else {
            try_move_file(entry, &to_pattern, &re)
        };

        if let Some(Err(e)) = move_result {
            exit_ok = false;
            eprintln!("{:?}", e);
        }
    }

    exit_ok
}

fn try_move_file(entry: DirEntry, target_pattern: &str, re: &Regex) -> Option<io::Result<()>> {
    let filename = entry.file_name().to_str()?;

    if !re.is_match(filename) {
        return None;
    }

    let replaced_name = re.replace(filename, target_pattern);
    let target_file_name: &str = replaced_name.borrow();
    let target_file_path = Path::new(target_file_name);

    Some(fs::rename(entry.path(), target_file_path))
}

fn try_copy_file(entry: DirEntry, target_pattern: &str, re: &Regex) -> Option<io::Result<()>> {
    let filename = entry.file_name().to_str()?;

    if !re.is_match(filename) {
        return None;
    }

    let replaced_name = re.replace(filename, target_pattern);
    let target_file_name: &str = replaced_name.borrow();
    let target_file_path = Path::new(target_file_name);

    return match fs::copy(entry.path(), target_file_path) {
        Ok(_) => Some(Ok(())),
        Err(e) => Some(Err(e)),
    };
}
<|endoftext|>


<commit_before>//! # Span Processor
//!
//! Span processor is an interface which allows hooks for span start and end
//! method invocations. Span processors are invoked only when [`is_recording`]
//! is `true`.
//! Built-in span processors are responsible for batching and conversion of
//! spans to exportable representation and passing batches to exporters.
//! Span processors can be registered directly on SDK [`TracerProvider`] and they are
//! invoked in the same order as they were registered.
//! All [`Tracer`] instances created by a [`TracerProvider`] share the same span
//! processors. Changes to this collection reflect in all [`Tracer`] instances.
//! The following diagram shows [`SpanProcessor`]'s relationship to other
//! components in the SDK:
//!
//! ```ascii
//! +-----+--------------+   +-------------------------+   +-------------------+
//! |     |              |   |                         |   |                   |
//! |     |              |   | BatchExporterProcessor  |   |    SpanExporter   |
//! |     |              +---> SimpleExporterProcessor +--->  (JaegerExporter) |
//! |     |              |   |                         |   |                   |
//! | SDK | Span.start() |   +-------------------------+   +-------------------+
//! |     | Span.end()   |
//! |     |              |   +---------------------+
//! |     |              |   |                     |
//! |     |              +---> ZPagesProcessor     |
//! |     |              |   |                     |
//! +-----+--------------+   +---------------------+
//! ```
//!
//! # Examples
//!
//! #### Exporting spans with a simple exporter:
//!
//! Note that the simple processor exports synchronously every time a span is ended. If you find this
//! limiting, consider the batch processor instead.
//!
//! ```
//! use opentelemetry::{api, sdk, global};
//!
//! // Configure your preferred exporter
//! let exporter = api::NoopSpanExporter {};
//!
//! // Then use the `with_simple_exporter` method to have the provider export when spans finish.
//! let provider = sdk::TracerProvider::builder()
//!     .with_simple_exporter(exporter)
//!     .build();
//!
//! global::set_provider(provider);
//! ```
//!
//! #### Exporting spans asynchronously in batches:
//!
//! This processor can be configured with an [`executor`] of your choice to batch and upload spans
//! asynchronously when they end. If you have added a library like [`tokio`] or [`async-std`], you
//! can pass in their respective `spawn` and `interval` functions to have batching performed in
//! those contexts.
//!
//! ```
//! use futures::{stream};
//! use opentelemetry::{api, sdk, global};
//! use std::time::Duration;
//!
//! #[tokio::main]
//! async fn main() {
//!     // Configure your preferred exporter
//!     let exporter = api::NoopSpanExporter {};
//!
//!     // Then build a batch processor. You can use whichever executor you have available, for
//!     // example if you are using `async-std` instead of `tokio` you can replace the spawn and
//!     // interval functions with `async_std::task::spawn` and `async_std::stream::interval`.
//!     let batch = sdk::BatchSpanProcessor::builder(exporter, tokio::spawn, tokio::time::interval)
//!         .with_max_queue_size(4096)
//!         .build();
//!
//!     // Then use the `with_batch_exporter` method to have the provider export spans in batches.
//!     let provider = sdk::TracerProvider::builder()
//!         .with_batch_exporter(batch)
//!         .build();
//!
//!     global::set_provider(provider);
//! }
//! ```
//!
//! [`is_recording`]: ../../../api/trace/span/trait.Span.html#tymethod.is_recording
//! [`TracerProvider`]: ../../../api/trace/provider/trait.TracerProvider.html
//! [`Tracer`]: ../../../api/trace/tracer/trait.Tracer.html
//! [`SpanProcessor`]: ../../../api/trace/span_processor/trait.SpanProcessor.html
//! [`SimpleSpanProcessor`]: struct.SimpleSpanProcessor.html
//! [`BatchSpanProcessor`]: struct.BatchSpanProcessor.html
//! [`executor`]: https://docs.rs/futures/0.3.4/futures/executor/index.html
//! [`tokio`]: https://tokio.rs
//! [`async-std`]: https://async.rs
use crate::{api, exporter};
use futures::{
    channel::mpsc,
    task::{Context, Poll},
    Future, Stream, StreamExt,
};
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::time;

/// A [`SpanProcessor`] that exports synchronously when spans are finished.
///
/// [`SpanProcessor`]: ../../../api/trace/span_processor/trait.SpanProcessor.html
#[derive(Debug)]
pub struct SimpleSpanProcessor {
    exporter: Box<dyn exporter::trace::SpanExporter>,
}

impl SimpleSpanProcessor {
    pub(crate) fn new(exporter: Box<dyn exporter::trace::SpanExporter>) -> Self {
        SimpleSpanProcessor { exporter }
    }
}

impl api::SpanProcessor for SimpleSpanProcessor {
    fn on_start(&self, _span: Arc<exporter::trace::SpanData>) {
        // Ignored
    }

    fn on_end(&self, span: Arc<exporter::trace::SpanData>) {
        if span.span_context.is_sampled() {
            self.exporter.export(vec![span]);
        }
    }

    fn shutdown(&self) {
        self.exporter.shutdown();
    }
}

/// A [`SpanProcessor`] that asynchronously buffers finished spans and reports
/// them at a preconfigured interval.
///
/// [`SpanProcessor`]: ../../../api/trace/span_processor/trait.SpanProcessor.html
#[derive(Debug)]
pub struct BatchSpanProcessor {
    message_sender: Mutex<mpsc::Sender<BatchMessage>>,
}

impl api::SpanProcessor for BatchSpanProcessor {
    fn on_start(&self, _span: Arc<exporter::trace::SpanData>) {
        // Ignored
    }

    fn on_end(&self, span: Arc<exporter::trace::SpanData>) {
        if let Ok(mut sender) = self.message_sender.lock() {
            let _ = sender.try_send(BatchMessage::ExportSpan(span));
        }
    }

    fn shutdown(&self) {
        if let Ok(mut sender) = self.message_sender.lock() {
            let _ = sender.try_send(BatchMessage::Shutdown);
        }
    }
}

/// A worker process that batches and processes spans as they are reported.
///
/// This process is implemented as a [`Future`] that returns when the accompanying
/// [`BatchSpanProcessor`] is shut down, and allows systems like [`tokio`] and [`async-std`] to
/// process the work in the background without requiring dedicated system threads.
#[allow(missing_debug_implementations)]
pub struct BatchSpanProcessorWorker {
    exporter: Box<dyn exporter::trace::SpanExporter>,
    messages: Pin<Box<dyn Stream<Item = BatchMessage> + Send>>,
    config: BatchConfig,
    buffer: Vec<Arc<exporter::trace::SpanData>>,
}

impl BatchSpanProcessorWorker {
    fn export_spans(&mut self) {
        if !self.buffer.is_empty() {
            let mut spans = std::mem::replace(&mut self.buffer, Vec::new());
            while !spans.is_empty() {
                let batch_idx = spans
                    .len()
                    .saturating_sub(self.config.max_export_batch_size);
                let batch = spans.split_off(batch_idx);
                self.exporter.export(batch);
            }
        }
    }
}

impl Drop for BatchSpanProcessorWorker {
    fn drop(&mut self) {
        self.export_spans();
    }
}

impl Future for BatchSpanProcessorWorker {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match futures::ready!(self.messages.poll_next_unpin(cx)) {
                // Span has finished, add to buffer of pending spans.
                Some(BatchMessage::ExportSpan(span)) => {
                    if self.buffer.len() < self.config.max_queue_size {
                        self.buffer.push(span);
                    }
                }
                // Span batch interval time reached, export current spans.
                Some(BatchMessage::Tick) => self.export_spans(),
                // Stream has terminated or processor is shutdown, return to finish execution.
                None | Some(BatchMessage::Shutdown) => {
                    self.exporter.shutdown();
                    return Poll::Ready(());
                }
            }
        }
    }
}

#[derive(Debug)]
enum BatchMessage {
    ExportSpan(Arc<exporter::trace::SpanData>),
    Tick,
    Shutdown,
}

impl BatchSpanProcessor {
    pub(crate) fn new<S, SO, I, IS, ISI>(
        exporter: Box<dyn exporter::trace::SpanExporter>,
        spawn: S,
        interval: I,
        config: BatchConfig,
    ) -> Self
    where
        S: Fn(BatchSpanProcessorWorker) -> SO,
        I: Fn(time::Duration) -> IS,
        IS: Stream<Item = ISI> + Send + 'static,
    {
        let (message_sender, message_receiver) = mpsc::channel(config.max_queue_size);
        let ticker = interval(config.scheduled_delay).map(|_| BatchMessage::Tick);

        // Spawn worker process via user-defined spawn function.
        spawn(BatchSpanProcessorWorker {
            exporter,
            messages: Box::pin(futures::stream::select(message_receiver, ticker)),
            config,
            buffer: Vec::new(),
        });

        // Return batch processor with link to worker
        BatchSpanProcessor {
            message_sender: Mutex::new(message_sender),
        }
    }

    /// Create a new batch processor builder
    pub fn builder<E, S, SO, I, IO>(
        exporter: E,
        spawn: S,
        interval: I,
    ) -> BatchSpanProcessorBuilder<E, S, I>
    where
        E: exporter::trace::SpanExporter,
        S: Fn(BatchSpanProcessorWorker) -> SO,
        I: Fn(time::Duration) -> IO,
    {
        BatchSpanProcessorBuilder {
            exporter,
            spawn,
            interval,
            config: Default::default(),
        }
    }
}

/// Batch span processor configuration
#[derive(Debug)]
pub struct BatchConfig {
    /// The maximum queue size to buffer spans for delayed processing. If the
    /// queue gets full it drops the spans. The default value of is 2048.
    max_queue_size: usize,

    /// The delay interval in milliseconds between two consecutive processing
    /// of batches. The default value is 5 seconds.
    scheduled_delay: time::Duration,

    /// The maximum number of spans to process in a single batch. If there are
    /// more than one batch worth of spans then it processes multiple batches
    /// of spans one batch after the other without any delay. The default value
    /// is 512.
    max_export_batch_size: usize,
}

impl Default for BatchConfig {
    fn default() -> Self {
        BatchConfig {
            max_queue_size: 2048,
            scheduled_delay: time::Duration::from_secs(5),
            max_export_batch_size: 512,
        }
    }
}

/// A builder for creating [`BatchSpanProcessor`] instances.
///
/// [`BatchSpanProcessor`]: struct.BatchSpanProcessor.html
#[derive(Debug)]
pub struct BatchSpanProcessorBuilder<E, S, I> {
    exporter: E,
    interval: I,
    spawn: S,
    config: BatchConfig,
}

impl<E, S, SO, I, IS, ISI> BatchSpanProcessorBuilder<E, S, I>
where
    E: exporter::trace::SpanExporter + 'static,
    S: Fn(BatchSpanProcessorWorker) -> SO,
    I: Fn(time::Duration) -> IS,
    IS: Stream<Item = ISI> + Send + 'static,
{
    /// Set max queue size for batches
    pub fn with_max_queue_size(self, size: usize) -> Self {
        let mut config = self.config;
        config.max_queue_size = size;

        BatchSpanProcessorBuilder { config, ..self }
    }

    /// Set scheduled delay for batches
    pub fn with_scheduled_delay(self, delay: time::Duration) -> Self {
        let mut config = self.config;
        config.scheduled_delay = delay;

        BatchSpanProcessorBuilder { config, ..self }
    }

    /// Set max export size for batches
    pub fn with_max_export_batch_size(self, size: usize) -> Self {
        let mut config = self.config;
        config.max_export_batch_size = size;

        BatchSpanProcessorBuilder { config, ..self }
    }

    /// Build a batch processor
    pub fn build(self) -> BatchSpanProcessor {
        BatchSpanProcessor::new(
            Box::new(self.exporter),
            self.spawn,
            self.interval,
            self.config,
        )
    }
}
<commit_msg>Add config options from env for BatchSpanProcessor (#228)<commit_after>//! # Span Processor
//!
//! Span processor is an interface which allows hooks for span start and end
//! method invocations. Span processors are invoked only when [`is_recording`]
//! is `true`.
//! Built-in span processors are responsible for batching and conversion of
//! spans to exportable representation and passing batches to exporters.
//! Span processors can be registered directly on SDK [`TracerProvider`] and they are
//! invoked in the same order as they were registered.
//! All [`Tracer`] instances created by a [`TracerProvider`] share the same span
//! processors. Changes to this collection reflect in all [`Tracer`] instances.
//! The following diagram shows [`SpanProcessor`]'s relationship to other
//! components in the SDK:
//!
//! ```ascii
//! +-----+--------------+   +-------------------------+   +-------------------+
//! |     |              |   |                         |   |                   |
//! |     |              |   | BatchExporterProcessor  |   |    SpanExporter   |
//! |     |              +---> SimpleExporterProcessor +--->  (JaegerExporter) |
//! |     |              |   |                         |   |                   |
//! | SDK | Span.start() |   +-------------------------+   +-------------------+
//! |     | Span.end()   |
//! |     |              |   +---------------------+
//! |     |              |   |                     |
//! |     |              +---> ZPagesProcessor     |
//! |     |              |   |                     |
//! +-----+--------------+   +---------------------+
//! ```
//!
//! # Examples
//!
//! #### Exporting spans with a simple exporter:
//!
//! Note that the simple processor exports synchronously every time a span is ended. If you find this
//! limiting, consider the batch processor instead.
//!
//! ```
//! use opentelemetry::{api, sdk, global};
//!
//! // Configure your preferred exporter
//! let exporter = api::NoopSpanExporter {};
//!
//! // Then use the `with_simple_exporter` method to have the provider export when spans finish.
//! let provider = sdk::TracerProvider::builder()
//!     .with_simple_exporter(exporter)
//!     .build();
//!
//! global::set_provider(provider);
//! ```
//!
//! #### Exporting spans asynchronously in batches:
//!
//! This processor can be configured with an [`executor`] of your choice to batch and upload spans
//! asynchronously when they end. If you have added a library like [`tokio`] or [`async-std`], you
//! can pass in their respective `spawn` and `interval` functions to have batching performed in
//! those contexts.
//!
//! ```
//! use futures::{stream};
//! use opentelemetry::{api, sdk, global};
//! use std::time::Duration;
//!
//! #[tokio::main]
//! async fn main() {
//!     // Configure your preferred exporter
//!     let exporter = api::NoopSpanExporter {};
//!
//!     // Then build a batch processor. You can use whichever executor you have available, for
//!     // example if you are using `async-std` instead of `tokio` you can replace the spawn and
//!     // interval functions with `async_std::task::spawn` and `async_std::stream::interval`.
//!     let batch = sdk::BatchSpanProcessor::builder(exporter, tokio::spawn, tokio::time::interval)
//!         .with_max_queue_size(4096)
//!         .build();
//!
//!     // Then use the `with_batch_exporter` method to have the provider export spans in batches.
//!     let provider = sdk::TracerProvider::builder()
//!         .with_batch_exporter(batch)
//!         .build();
//!
//!     global::set_provider(provider);
//! }
//! ```
//!
//! [`is_recording`]: ../../../api/trace/span/trait.Span.html#tymethod.is_recording
//! [`TracerProvider`]: ../../../api/trace/provider/trait.TracerProvider.html
//! [`Tracer`]: ../../../api/trace/tracer/trait.Tracer.html
//! [`SpanProcessor`]: ../../../api/trace/span_processor/trait.SpanProcessor.html
//! [`SimpleSpanProcessor`]: struct.SimpleSpanProcessor.html
//! [`BatchSpanProcessor`]: struct.BatchSpanProcessor.html
//! [`executor`]: https://docs.rs/futures/0.3.4/futures/executor/index.html
//! [`tokio`]: https://tokio.rs
//! [`async-std`]: https://async.rs
use crate::{api, exporter};
use futures::{
    channel::mpsc,
    task::{Context, Poll},
    Future, Stream, StreamExt,
};
use std::pin::Pin;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::time;

/// Delay interval between two consecutive exports, default to be 5000.
const OTEL_BSP_SCHEDULE_DELAY_MILLIS: &str = "OTEL_BSP_SCHEDULE_DELAY_MILLIS";
/// Default delay interval between two consecutive exports.
const OTEL_BSP_SCHEDULE_DELAY_MILLIS_DEFAULT: u64 = 5000;
/// Maximum queue size, default to be 2048
const OTEL_BSP_MAX_QUEUE_SIZE: &str = "OTEL_BSP_MAX_QUEUE_SIZE";
/// Default maximum queue size
const OTEL_BSP_MAX_QUEUE_SIZE_DEFAULT: usize = 2048;
/// Maximum batch size, must be less than or equal to OTEL_BSP_MAX_QUEUE_SIZE, default to be 512
const OTEL_BSP_MAX_EXPORT_BATCH_SIZE: &str = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE";
/// Default maximum batch size
const OTEL_BSP_MAX_EXPORT_BATCH_SIZE_DEFAULT: usize = 512;

/// A [`SpanProcessor`] that exports synchronously when spans are finished.
///
/// [`SpanProcessor`]: ../../../api/trace/span_processor/trait.SpanProcessor.html
#[derive(Debug)]
pub struct SimpleSpanProcessor {
    exporter: Box<dyn exporter::trace::SpanExporter>,
}

impl SimpleSpanProcessor {
    pub(crate) fn new(exporter: Box<dyn exporter::trace::SpanExporter>) -> Self {
        SimpleSpanProcessor { exporter }
    }
}

impl api::SpanProcessor for SimpleSpanProcessor {
    fn on_start(&self, _span: Arc<exporter::trace::SpanData>) {
        // Ignored
    }

    fn on_end(&self, span: Arc<exporter::trace::SpanData>) {
        if span.span_context.is_sampled() {
            self.exporter.export(vec![span]);
        }
    }

    fn shutdown(&self) {
        self.exporter.shutdown();
    }
}

/// A [`SpanProcessor`] that asynchronously buffers finished spans and reports
/// them at a preconfigured interval.
///
/// [`SpanProcessor`]: ../../../api/trace/span_processor/trait.SpanProcessor.html
#[derive(Debug)]
pub struct BatchSpanProcessor {
    message_sender: Mutex<mpsc::Sender<BatchMessage>>,
}

impl api::SpanProcessor for BatchSpanProcessor {
    fn on_start(&self, _span: Arc<exporter::trace::SpanData>) {
        // Ignored
    }

    fn on_end(&self, span: Arc<exporter::trace::SpanData>) {
        if let Ok(mut sender) = self.message_sender.lock() {
            let _ = sender.try_send(BatchMessage::ExportSpan(span));
        }
    }

    fn shutdown(&self) {
        if let Ok(mut sender) = self.message_sender.lock() {
            let _ = sender.try_send(BatchMessage::Shutdown);
        }
    }
}

/// A worker process that batches and processes spans as they are reported.
///
/// This process is implemented as a [`Future`] that returns when the accompanying
/// [`BatchSpanProcessor`] is shut down, and allows systems like [`tokio`] and [`async-std`] to
/// process the work in the background without requiring dedicated system threads.
#[allow(missing_debug_implementations)]
pub struct BatchSpanProcessorWorker {
    exporter: Box<dyn exporter::trace::SpanExporter>,
    messages: Pin<Box<dyn Stream<Item = BatchMessage> + Send>>,
    config: BatchConfig,
    buffer: Vec<Arc<exporter::trace::SpanData>>,
}

impl BatchSpanProcessorWorker {
    fn export_spans(&mut self) {
        if !self.buffer.is_empty() {
            let mut spans = std::mem::replace(&mut self.buffer, Vec::new());
            while !spans.is_empty() {
                let batch_idx = spans
                    .len()
                    .saturating_sub(self.config.max_export_batch_size);
                let batch = spans.split_off(batch_idx);
                self.exporter.export(batch);
            }
        }
    }
}

impl Drop for BatchSpanProcessorWorker {
    fn drop(&mut self) {
        self.export_spans();
    }
}

impl Future for BatchSpanProcessorWorker {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match futures::ready!(self.messages.poll_next_unpin(cx)) {
                // Span has finished, add to buffer of pending spans.
                Some(BatchMessage::ExportSpan(span)) => {
                    if self.buffer.len() < self.config.max_queue_size {
                        self.buffer.push(span);
                    }
                }
                // Span batch interval time reached, export current spans.
                Some(BatchMessage::Tick) => self.export_spans(),
                // Stream has terminated or processor is shutdown, return to finish execution.
                None | Some(BatchMessage::Shutdown) => {
                    self.exporter.shutdown();
                    return Poll::Ready(());
                }
            }
        }
    }
}

#[derive(Debug)]
enum BatchMessage {
    ExportSpan(Arc<exporter::trace::SpanData>),
    Tick,
    Shutdown,
}

impl BatchSpanProcessor {
    pub(crate) fn new<S, SO, I, IS, ISI>(
        exporter: Box<dyn exporter::trace::SpanExporter>,
        spawn: S,
        interval: I,
        config: BatchConfig,
    ) -> Self
    where
        S: Fn(BatchSpanProcessorWorker) -> SO,
        I: Fn(time::Duration) -> IS,
        IS: Stream<Item = ISI> + Send + 'static,
    {
        let (message_sender, message_receiver) = mpsc::channel(config.max_queue_size);
        let ticker = interval(config.scheduled_delay).map(|_| BatchMessage::Tick);

        // Spawn worker process via user-defined spawn function.
        spawn(BatchSpanProcessorWorker {
            exporter,
            messages: Box::pin(futures::stream::select(message_receiver, ticker)),
            config,
            buffer: Vec::new(),
        });

        // Return batch processor with link to worker
        BatchSpanProcessor {
            message_sender: Mutex::new(message_sender),
        }
    }

    /// Create a new batch processor builder
    pub fn builder<E, S, SO, I, IO>(
        exporter: E,
        spawn: S,
        interval: I,
    ) -> BatchSpanProcessorBuilder<E, S, I>
    where
        E: exporter::trace::SpanExporter,
        S: Fn(BatchSpanProcessorWorker) -> SO,
        I: Fn(time::Duration) -> IO,
    {
        BatchSpanProcessorBuilder {
            exporter,
            spawn,
            interval,
            config: Default::default(),
        }
    }

    /// Create a new batch processor builder and set the config value based on environment variables.
    ///
    /// If the value in environment variables is illegal, will fall back to use default value.
    ///
    /// Note that export batch size should be less than or equals to max queue size.
    /// If export batch size is larger than max queue size, we will lower to be the same as max
    /// queue size
    pub fn from_env<E, S, SO, I, IO>(
        exporter: E,
        spawn: S,
        interval: I,
    ) -> BatchSpanProcessorBuilder<E, S, I>
    where
        E: exporter::trace::SpanExporter,
        S: Fn(BatchSpanProcessorWorker) -> SO,
        I: Fn(time::Duration) -> IO,
    {
        let mut config = BatchConfig::default();
        let schedule_delay = std::env::var(OTEL_BSP_SCHEDULE_DELAY_MILLIS)
            .map(|delay| u64::from_str(&delay).unwrap_or(OTEL_BSP_SCHEDULE_DELAY_MILLIS_DEFAULT))
            .unwrap_or(OTEL_BSP_SCHEDULE_DELAY_MILLIS_DEFAULT);
        config.scheduled_delay = time::Duration::from_millis(schedule_delay);

        let max_queue_size = std::env::var(OTEL_BSP_MAX_QUEUE_SIZE)
            .map(|queue_size| {
                usize::from_str(&queue_size).unwrap_or(OTEL_BSP_MAX_QUEUE_SIZE_DEFAULT)
            })
            .unwrap_or(OTEL_BSP_MAX_QUEUE_SIZE_DEFAULT);
        config.max_queue_size = max_queue_size;

        let max_export_batch_size = std::env::var(OTEL_BSP_MAX_EXPORT_BATCH_SIZE)
            .map(|batch_size| {
                usize::from_str(&batch_size).unwrap_or(OTEL_BSP_MAX_EXPORT_BATCH_SIZE_DEFAULT)
            })
            .unwrap_or(OTEL_BSP_MAX_EXPORT_BATCH_SIZE_DEFAULT);
        // max export batch size must be less or equal to max queue size.
        // we set max export batch size to max queue size if it's larger than max queue size.
        if max_export_batch_size > max_queue_size {
            config.max_export_batch_size = max_queue_size;
        } else {
            config.max_export_batch_size = max_export_batch_size;
        }

        BatchSpanProcessorBuilder {
            config,
            exporter,
            spawn,
            interval,
        }
    }
}

/// Batch span processor configuration
#[derive(Debug)]
pub struct BatchConfig {
    /// The maximum queue size to buffer spans for delayed processing. If the
    /// queue gets full it drops the spans. The default value of is 2048.
    max_queue_size: usize,

    /// The delay interval in milliseconds between two consecutive processing
    /// of batches. The default value is 5 seconds.
    scheduled_delay: time::Duration,

    /// The maximum number of spans to process in a single batch. If there are
    /// more than one batch worth of spans then it processes multiple batches
    /// of spans one batch after the other without any delay. The default value
    /// is 512.
    max_export_batch_size: usize,
}

impl Default for BatchConfig {
    fn default() -> Self {
        BatchConfig {
            max_queue_size: OTEL_BSP_MAX_QUEUE_SIZE_DEFAULT,
            scheduled_delay: time::Duration::from_millis(OTEL_BSP_SCHEDULE_DELAY_MILLIS_DEFAULT),
            max_export_batch_size: OTEL_BSP_MAX_EXPORT_BATCH_SIZE_DEFAULT,
        }
    }
}

/// A builder for creating [`BatchSpanProcessor`] instances.
///
/// [`BatchSpanProcessor`]: struct.BatchSpanProcessor.html
#[derive(Debug)]
pub struct BatchSpanProcessorBuilder<E, S, I> {
    exporter: E,
    interval: I,
    spawn: S,
    config: BatchConfig,
}

impl<E, S, SO, I, IS, ISI> BatchSpanProcessorBuilder<E, S, I>
where
    E: exporter::trace::SpanExporter + 'static,
    S: Fn(BatchSpanProcessorWorker) -> SO,
    I: Fn(time::Duration) -> IS,
    IS: Stream<Item = ISI> + Send + 'static,
{
    /// Set max queue size for batches
    pub fn with_max_queue_size(self, size: usize) -> Self {
        let mut config = self.config;
        config.max_queue_size = size;

        BatchSpanProcessorBuilder { config, ..self }
    }

    /// Set scheduled delay for batches
    pub fn with_scheduled_delay(self, delay: time::Duration) -> Self {
        let mut config = self.config;
        config.scheduled_delay = delay;

        BatchSpanProcessorBuilder { config, ..self }
    }

    /// Set max export size for batches, should always less than or equals to max queue size.
    ///
    /// If input is larger than max queue size, will lower it to be equal to max queue size
    pub fn with_max_export_batch_size(self, size: usize) -> Self {
        let mut config = self.config;
        if size > config.max_queue_size {
            config.max_export_batch_size = config.max_queue_size;
        } else {
            config.max_export_batch_size = size;
        }

        BatchSpanProcessorBuilder { config, ..self }
    }

    /// Build a batch processor
    pub fn build(self) -> BatchSpanProcessor {
        BatchSpanProcessor::new(
            Box::new(self.exporter),
            self.spawn,
            self.interval,
            self.config,
        )
    }
}

#[cfg(test)]
mod tests {
    use crate::exporter::trace::stdout;
    use crate::sdk::trace::span_processor::{
        OTEL_BSP_MAX_EXPORT_BATCH_SIZE, OTEL_BSP_MAX_QUEUE_SIZE,
        OTEL_BSP_MAX_QUEUE_SIZE_DEFAULT, OTEL_BSP_SCHEDULE_DELAY_MILLIS,
        OTEL_BSP_SCHEDULE_DELAY_MILLIS_DEFAULT,
    };
    use crate::sdk::BatchSpanProcessor;
    use std::time;

    #[test]
    fn test_build_batch_span_processor_from_env() {
        std::env::set_var(OTEL_BSP_MAX_EXPORT_BATCH_SIZE, "500");
        std::env::set_var(OTEL_BSP_SCHEDULE_DELAY_MILLIS, "I am not number");

        let mut builder = BatchSpanProcessor::from_env(
            stdout::Exporter::new(std::io::stdout(), true),
            tokio::spawn,
            tokio::time::interval,
        );
        // export batch size cannot exceed max queue size
        assert_eq!(builder.config.max_export_batch_size, 500);
        assert_eq!(
            builder.config.scheduled_delay,
            time::Duration::from_millis(OTEL_BSP_SCHEDULE_DELAY_MILLIS_DEFAULT)
        );
        assert_eq!(
            builder.config.max_queue_size,
            OTEL_BSP_MAX_QUEUE_SIZE_DEFAULT
        );

        std::env::set_var(OTEL_BSP_MAX_QUEUE_SIZE, "120");
        builder = BatchSpanProcessor::from_env(
            stdout::Exporter::new(std::io::stdout(), true),
            tokio::spawn,
            tokio::time::interval,
        );

        assert_eq!(builder.config.max_export_batch_size, 120);
        assert_eq!(builder.config.max_queue_size, 120);
    }
}
<|endoftext|>


<commit_before>extern mod sdl2;

use std::vec;

use sdl2::pixels;
use sdl2::render;
use sdl2::video;

pub struct App {
    priv renderer: ~render::Renderer,
    priv texture: ~render::Texture,

    pixels: ~[u8],
    priv width: uint,
    priv height: uint,
}

impl App {
    pub fn new(title: ~str, width: uint, height: uint) -> Result<~App, ~str> {
        sdl2::init([sdl2::InitVideo]);

        let window = match video::Window::new(title,
            sdl2::video::PosCentered, sdl2::video::PosCentered,
            width as int, height as int, [video::OpenGL]) {
            Ok(window) => window,
            Err(err) => return Err(format!("SDL2 window fail: {}", err))
        };
        let renderer = match render::Renderer::from_window(window,
            render::DriverAuto, [render::Accelerated]) {
            Ok(renderer) => renderer,
            Err(err) => return Err(format!("SDL2 renderer fail: {}", err))
        };
        let texture = match renderer.create_texture(pixels::ARGB8888,
            render::AccessStreaming, width as int, height as int) {
            Ok(texture) => texture,
            Err(err) => return Err(format!("SDL2 texture fail: {}", err))
        };
        let pixels = vec::from_elem(width * height * 4, 0u8);
        Ok(~App{
            renderer: renderer,
            texture: texture,
            pixels: pixels,
            width: width,
            height: height,
        })
    }

    pub fn render(&self) {
        self.renderer.clear();
        self.texture.update(None, self.pixels, self.width as int * 4);
        self.renderer.copy(self.texture, None, None);
        self.renderer.present();
    }
}

<commit_msg>Pixel perfect window resize in SDL2 app<commit_after>extern mod sdl2;

use std::vec;

use sdl2::pixels;
use sdl2::render;
use sdl2::video;
use sdl2::rect::Rect;

pub struct App {
    priv renderer: ~render::Renderer,
    priv texture: ~render::Texture,
    priv width: uint,
    priv height: uint,

    // Screen buffer to write to.
    pixels: ~[u8],

    // When true, making the window bigger will only make the pixels grow in
    // integer multiples. Keeps pixel art pretty.
    pixelPerfect: bool, }

impl App {
    pub fn new(title: ~str, width: uint, height: uint) -> Result<~App, ~str> {
        sdl2::init([sdl2::InitVideo]);

        let window = match video::Window::new(title,
            sdl2::video::PosCentered, sdl2::video::PosCentered,
            width as int, height as int, [video::Shown, video::Resizable]) {
            Ok(window) => window,
            Err(err) => return Err(format!("SDL2 window fail: {}", err))
        };
        let renderer = match render::Renderer::from_window(window,
            render::DriverAuto, [render::Accelerated, render::PresentVSync]) {
            Ok(renderer) => renderer,
            Err(err) => return Err(format!("SDL2 renderer fail: {}", err))
        };
        let texture = match renderer.create_texture(pixels::ARGB8888,
            render::AccessStreaming, width as int, height as int) {
            Ok(texture) => texture,
            Err(err) => return Err(format!("SDL2 texture fail: {}", err))
        };
        let pixels = vec::from_elem(width * height * 4, 0u8);
        Ok(~App{
            renderer: renderer,
            texture: texture,
            width: width,
            height: height,
            pixels: pixels,
            pixelPerfect: true,
        })
    }

    fn targetRect(&self) -> Rect {
        let port = self.renderer.get_viewport();

        let (w, h) = targetSize(self.width, self.height, &port, self.pixelPerfect);
        Rect{
            x: ((port.w as uint - w) / 2) as i32, y: ((port.h as uint - h) / 2) as i32,
            w: w as i32, h: h as i32
        }
    }

    pub fn render(&self) {
        self.renderer.clear();
        self.texture.update(None, self.pixels, self.width as int * 4);
        self.renderer.copy(self.texture, None, Some(self.targetRect()));
        self.renderer.present();
    }
}

fn targetSize(width: uint, height: uint, port: &Rect, pixelPerfect: bool) -> (uint, uint) {
    let wScale = port.w as f64 / width as f64;
    let hScale = port.h as f64 / height as f64;
    let minScale = if wScale < hScale { wScale } else { hScale };

    if minScale < 1.0 || !pixelPerfect {
         // Less than 1 physical pixel for 1 logical pixel, can't achieve
         // pixel perfection so just scale to what we get.
        ((width as f64 * minScale) as uint,
         (height as f64 * minScale) as uint)
    } else {
        ((width as f64 * minScale.floor()) as uint,
         (height as f64 * minScale.floor()) as uint)
    }
}
<|endoftext|>