<commit_before>use crate::alloc::borrow::Cow;
use crate::{Relocation, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap};
use target_lexicon::{Architecture, Endianness};
use uuid::Uuid;

/// An object file.
pub trait Object<'data, 'file> {
    /// A segment in the object file.
    type Segment: ObjectSegment<'data>;

    /// An iterator over the segments in the object file.
    type SegmentIterator: Iterator<Item = Self::Segment>;

    /// A section in the object file.
    type Section: ObjectSection<'data>;

    /// An iterator over the sections in the object file.
    type SectionIterator: Iterator<Item = Self::Section>;

    /// An iterator over the symbols in the object file.
    type SymbolIterator: Iterator<Item = (SymbolIndex, Symbol<'data>)>;

    /// Get the architecture type of the file.
    fn architecture(&self) -> Architecture;

    /// Get the endianness of the file.
    #[inline]
    fn endianness(&self) -> Endianness {
        if self.is_little_endian() {
            Endianness::Little
        } else {
            Endianness::Big
        }
    }

    /// Return true if the file is little endian, false if it is big endian.
    fn is_little_endian(&self) -> bool;

    /// Return true if the file can contain 64-bit addresses.
    fn is_64(&self) -> bool;

    /// Get an iterator over the segments in the file.
    fn segments(&'file self) -> Self::SegmentIterator;

    /// Get the entry point address of the binary
    fn entry(&'file self) -> u64;

    /// Get the section named `section_name`, if such a section exists.
    ///
    /// If `section_name` starts with a '.' then it is treated as a system section name,
    /// and is compared using the conventions specific to the object file format. This
    /// includes:
    /// - if ".text" is requested for a Mach-O object file, then the actual
    /// section name that is searched for is "__text".
    /// - if ".debug_info" is requested for an ELF object file, then
    /// ".zdebug_info" may be returned (and similarly for other debug sections).
    ///
    /// For some object files, multiple segments may contain sections with the same
    /// name. In this case, the first matching section will be used.
    fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;

    /// Get the section at the given index.
    ///
    /// The meaning of the index depends on the object file.
    ///
    /// For some object files, this requires iterating through all sections.
    fn section_by_index(&'file self, index: SectionIndex) -> Option<Self::Section>;

    /// Get the contents of the section named `section_name`, if such
    /// a section exists.
    ///
    /// The `section_name` is interpreted according to `Self::section_by_name`.
    ///
    /// This may decompress section data.
    fn section_data_by_name(&'file self, section_name: &str) -> Option<Cow<'data, [u8]>> {
        self.section_by_name(section_name)
            .map(|section| section.uncompressed_data())
    }

    /// Get an iterator over the sections in the file.
    fn sections(&'file self) -> Self::SectionIterator;

    /// Get the debugging symbol at the given index.
    ///
    /// This is similar to `self.symbols().nth(index)`, except that
    /// the index will take into account malformed or unsupported symbols.
    fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>;

    /// Get an iterator over the debugging symbols in the file.
    ///
    /// This may skip over symbols that are malformed or unsupported.
    fn symbols(&'file self) -> Self::SymbolIterator;

    /// Get the data for the given symbol.
    fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Option<&'data [u8]> {
        if symbol.is_undefined() {
            return None;
        }
        let address = symbol.address();
        let size = symbol.size();
        if let Some(index) = symbol.section_index() {
            self.section_by_index(index)
                .and_then(|section| section.data_range(address, size))
        } else {
            self.segments()
                .find_map(|segment| segment.data_range(address, size))
        }
    }

    /// Get an iterator over the dynamic linking symbols in the file.
    ///
    /// This may skip over symbols that are malformed or unsupported.
    fn dynamic_symbols(&'file self) -> Self::SymbolIterator;

    /// Construct a map from addresses to symbols.
    fn symbol_map(&self) -> SymbolMap<'data>;

    /// Return true if the file contains debug information sections, false if not.
    fn has_debug_symbols(&self) -> bool;

    /// The UUID from a Mach-O `LC_UUID` load command.
    #[inline]
    fn mach_uuid(&self) -> Option<Uuid> {
        None
    }

    /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
    #[inline]
    fn build_id(&self) -> Option<&'data [u8]> {
        None
    }

    /// The filename and CRC from a `.gnu_debuglink` section.
    #[inline]
    fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> {
        None
    }
}

/// A loadable segment defined in an object file.
///
/// For ELF, this is a program header with type `PT_LOAD`.
/// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
pub trait ObjectSegment<'data> {
    /// Returns the virtual address of the segment.
    fn address(&self) -> u64;

    /// Returns the size of the segment in memory.
    fn size(&self) -> u64;

    /// Returns the alignment of the segment in memory.
    fn align(&self) -> u64;

    /// Returns the offset and size of the segment in the file.
    fn file_range(&self) -> (u64, u64);

    /// Returns a reference to the file contents of the segment.
    /// The length of this data may be different from the size of the
    /// segment in memory.
    fn data(&self) -> &'data [u8];

    /// Return the segment data in the given range.
    fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>;

    /// Returns the name of the segment.
    fn name(&self) -> Option<&str>;
}

/// A section defined in an object file.
pub trait ObjectSection<'data> {
    /// An iterator over the relocations for a section.
    ///
    /// The first field in the item tuple is the section offset
    /// that the relocation applies to.
    type RelocationIterator: Iterator<Item = (u64, Relocation)>;

    /// Returns the section index.
    fn index(&self) -> SectionIndex;

    /// Returns the address of the section.
    fn address(&self) -> u64;

    /// Returns the size of the section in memory.
    fn size(&self) -> u64;

    /// Returns the alignment of the section in memory.
    fn align(&self) -> u64;

    /// Returns offset and size of on-disk segment (if any)
    fn file_range(&self) -> Option<(u64, u64)>;

    /// Returns the raw contents of the section.
    /// The length of this data may be different from the size of the
    /// section in memory.
    ///
    /// This does not do any decompression.
    fn data(&self) -> Cow<'data, [u8]>;

    /// Return the raw contents of the section data in the given range.
    ///
    /// This does not do any decompression.
    fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>;

    /// Returns the uncompressed contents of the section.
    /// The length of this data may be different from the size of the
    /// section in memory.
    fn uncompressed_data(&self) -> Cow<'data, [u8]>;

    /// Returns the name of the section.
    fn name(&self) -> Option<&str>;

    /// Returns the name of the segment for this section.
    fn segment_name(&self) -> Option<&str>;

    /// Return the kind of this section.
    fn kind(&self) -> SectionKind;

    /// Get the relocations for this section.
    fn relocations(&self) -> Self::RelocationIterator;
}
<commit_msg>Tiny comment punctuation fix.<commit_after>use crate::alloc::borrow::Cow;
use crate::{Relocation, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap};
use target_lexicon::{Architecture, Endianness};
use uuid::Uuid;

/// An object file.
pub trait Object<'data, 'file> {
    /// A segment in the object file.
    type Segment: ObjectSegment<'data>;

    /// An iterator over the segments in the object file.
    type SegmentIterator: Iterator<Item = Self::Segment>;

    /// A section in the object file.
    type Section: ObjectSection<'data>;

    /// An iterator over the sections in the object file.
    type SectionIterator: Iterator<Item = Self::Section>;

    /// An iterator over the symbols in the object file.
    type SymbolIterator: Iterator<Item = (SymbolIndex, Symbol<'data>)>;

    /// Get the architecture type of the file.
    fn architecture(&self) -> Architecture;

    /// Get the endianness of the file.
    #[inline]
    fn endianness(&self) -> Endianness {
        if self.is_little_endian() {
            Endianness::Little
        } else {
            Endianness::Big
        }
    }

    /// Return true if the file is little endian, false if it is big endian.
    fn is_little_endian(&self) -> bool;

    /// Return true if the file can contain 64-bit addresses.
    fn is_64(&self) -> bool;

    /// Get an iterator over the segments in the file.
    fn segments(&'file self) -> Self::SegmentIterator;

    /// Get the entry point address of the binary
    fn entry(&'file self) -> u64;

    /// Get the section named `section_name`, if such a section exists.
    ///
    /// If `section_name` starts with a '.' then it is treated as a system section name,
    /// and is compared using the conventions specific to the object file format. This
    /// includes:
    /// - if ".text" is requested for a Mach-O object file, then the actual
    /// section name that is searched for is "__text".
    /// - if ".debug_info" is requested for an ELF object file, then
    /// ".zdebug_info" may be returned (and similarly for other debug sections).
    ///
    /// For some object files, multiple segments may contain sections with the same
    /// name. In this case, the first matching section will be used.
    fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;

    /// Get the section at the given index.
    ///
    /// The meaning of the index depends on the object file.
    ///
    /// For some object files, this requires iterating through all sections.
    fn section_by_index(&'file self, index: SectionIndex) -> Option<Self::Section>;

    /// Get the contents of the section named `section_name`, if such
    /// a section exists.
    ///
    /// The `section_name` is interpreted according to `Self::section_by_name`.
    ///
    /// This may decompress section data.
    fn section_data_by_name(&'file self, section_name: &str) -> Option<Cow<'data, [u8]>> {
        self.section_by_name(section_name)
            .map(|section| section.uncompressed_data())
    }

    /// Get an iterator over the sections in the file.
    fn sections(&'file self) -> Self::SectionIterator;

    /// Get the debugging symbol at the given index.
    ///
    /// This is similar to `self.symbols().nth(index)`, except that
    /// the index will take into account malformed or unsupported symbols.
    fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>;

    /// Get an iterator over the debugging symbols in the file.
    ///
    /// This may skip over symbols that are malformed or unsupported.
    fn symbols(&'file self) -> Self::SymbolIterator;

    /// Get the data for the given symbol.
    fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Option<&'data [u8]> {
        if symbol.is_undefined() {
            return None;
        }
        let address = symbol.address();
        let size = symbol.size();
        if let Some(index) = symbol.section_index() {
            self.section_by_index(index)
                .and_then(|section| section.data_range(address, size))
        } else {
            self.segments()
                .find_map(|segment| segment.data_range(address, size))
        }
    }

    /// Get an iterator over the dynamic linking symbols in the file.
    ///
    /// This may skip over symbols that are malformed or unsupported.
    fn dynamic_symbols(&'file self) -> Self::SymbolIterator;

    /// Construct a map from addresses to symbols.
    fn symbol_map(&self) -> SymbolMap<'data>;

    /// Return true if the file contains debug information sections, false if not.
    fn has_debug_symbols(&self) -> bool;

    /// The UUID from a Mach-O `LC_UUID` load command.
    #[inline]
    fn mach_uuid(&self) -> Option<Uuid> {
        None
    }

    /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
    #[inline]
    fn build_id(&self) -> Option<&'data [u8]> {
        None
    }

    /// The filename and CRC from a `.gnu_debuglink` section.
    #[inline]
    fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> {
        None
    }
}

/// A loadable segment defined in an object file.
///
/// For ELF, this is a program header with type `PT_LOAD`.
/// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
pub trait ObjectSegment<'data> {
    /// Returns the virtual address of the segment.
    fn address(&self) -> u64;

    /// Returns the size of the segment in memory.
    fn size(&self) -> u64;

    /// Returns the alignment of the segment in memory.
    fn align(&self) -> u64;

    /// Returns the offset and size of the segment in the file.
    fn file_range(&self) -> (u64, u64);

    /// Returns a reference to the file contents of the segment.
    /// The length of this data may be different from the size of the
    /// segment in memory.
    fn data(&self) -> &'data [u8];

    /// Return the segment data in the given range.
    fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>;

    /// Returns the name of the segment.
    fn name(&self) -> Option<&str>;
}

/// A section defined in an object file.
pub trait ObjectSection<'data> {
    /// An iterator over the relocations for a section.
    ///
    /// The first field in the item tuple is the section offset
    /// that the relocation applies to.
    type RelocationIterator: Iterator<Item = (u64, Relocation)>;

    /// Returns the section index.
    fn index(&self) -> SectionIndex;

    /// Returns the address of the section.
    fn address(&self) -> u64;

    /// Returns the size of the section in memory.
    fn size(&self) -> u64;

    /// Returns the alignment of the section in memory.
    fn align(&self) -> u64;

    /// Returns offset and size of on-disk segment (if any).
    fn file_range(&self) -> Option<(u64, u64)>;

    /// Returns the raw contents of the section.
    /// The length of this data may be different from the size of the
    /// section in memory.
    ///
    /// This does not do any decompression.
    fn data(&self) -> Cow<'data, [u8]>;

    /// Return the raw contents of the section data in the given range.
    ///
    /// This does not do any decompression.
    fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>;

    /// Returns the uncompressed contents of the section.
    /// The length of this data may be different from the size of the
    /// section in memory.
    fn uncompressed_data(&self) -> Cow<'data, [u8]>;

    /// Returns the name of the section.
    fn name(&self) -> Option<&str>;

    /// Returns the name of the segment for this section.
    fn segment_name(&self) -> Option<&str>;

    /// Return the kind of this section.
    fn kind(&self) -> SectionKind;

    /// Get the relocations for this section.
    fn relocations(&self) -> Self::RelocationIterator;
}
<|endoftext|>


<commit_before>use std::{
    future::Future,
    io::{self, Error},
    time::Duration,
};

use tokio::time;

pub async fn try_timeout<T, E, F>(fut: F, timeout: Option<Duration>) -> io::Result<T>
where
    F: Future<Output = Result<T, E>>,
    Error: From<E>,
{
    match timeout {
        Some(t) => time::timeout(t, fut).await?,
        None => fut.await,
    }
    .map_err(From::from)
}

#[cfg(unix)]
pub fn set_nofile(nofile: u64) -> io::Result<()> {
    unsafe {
        // set both soft and hard limit
        let lim = libc::rlimit {
            rlim_cur: nofile,
            rlim_max: nofile,
        };

        if libc::setrlimit(libc::RLIMIT_NOFILE, &lim as *const _) < 0 {
            return Err(Error::last_os_error());
        }
    }

    Ok(())
}

#[cfg(not(unix))]
pub fn set_nofile(_nofile: u64) -> io::Result<()> {
    // set_rlimit only works on *nix systems
    //
    // Windows' limit of opening files is the size of HANDLE (32-bits), so it is unlimited
    Ok(())
}
<commit_msg>Disable set_nofile in Android build<commit_after>use std::{
    future::Future,
    io::{self, Error},
    time::Duration,
};

use tokio::time;

pub async fn try_timeout<T, E, F>(fut: F, timeout: Option<Duration>) -> io::Result<T>
where
    F: Future<Output = Result<T, E>>,
    Error: From<E>,
{
    match timeout {
        Some(t) => time::timeout(t, fut).await?,
        None => fut.await,
    }
    .map_err(From::from)
}

#[cfg(all(unix, not(target_os="android")))]
pub fn set_nofile(nofile: u64) -> io::Result<()> {
    unsafe {
        // set both soft and hard limit
        let lim = libc::rlimit {
            rlim_cur: nofile,
            rlim_max: nofile,
        };

        if libc::setrlimit(libc::RLIMIT_NOFILE, &lim as *const _) < 0 {
            return Err(Error::last_os_error());
        }
    }

    Ok(())
}

#[cfg(any(not(unix), target_os="android"))]
pub fn set_nofile(_nofile: u64) -> io::Result<()> {
    // set_rlimit only works on *nix systems
    //
    // Windows' limit of opening files is the size of HANDLE (32-bits), so it is unlimited
    Ok(())
}
<|endoftext|>


<commit_before>use std::fs::read_to_string;
use crate::traces::TraceMap;
use crate::config::Config;
use crate::errors::RunError;

pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
  for (path, traces) in coverage_data.iter() {
    let content = match read_to_string(path) {
        Ok(k) => k,
        Err(e) => {
            return Err(RunError::Info(format!(
                "Unable to read source file to string: {}",
                e.to_string()
            )))
        }
    };

    println!("{:?}", traces);
  }

  Ok(())
}<commit_msg>lcov.info file done<commit_after>use crate::config::Config;
use crate::errors::RunError;
use crate::traces::{TraceMap, CoverageStat};
use std::fs::File;
use std::io::Write;

pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
    let file_path = config.output_directory.join("lcov.info");
    let mut file = match File::create(file_path) {
        Ok(k) => k,
        Err(e) => {
            return Err(RunError::Info(format!(
                "File is not writeable: {}",
                e.to_string()
            )))
        }
    };

    for (path, traces) in coverage_data.iter() {
        writeln!(file, "TN:")?;
        writeln!(file, "SF:{}", path.to_str().unwrap())?;

        let mut fns: Vec<String> = vec![];
        let mut fnda: Vec<String> = vec![];
        let mut da: Vec<String> = vec![];

        for trace in traces {
            if trace.fn_name.is_some() {
                let fn_name = trace.fn_name.clone().unwrap();
                let fn_hits = match trace.stats {
                    CoverageStat::Line(hits) => hits,
                    _ => return Err(RunError::Info(
                        "Function doesn't have hits number".to_string(),
                    )),
                };

                fns.push(format!("FN:{},{}", trace.line, fn_name));
                fnda.push(format!("FNDA:{},{}", fn_hits, fn_name));
            }

            match trace.stats {
                CoverageStat::Line(hits) => {
                    da.push(format!("DA:{},{}", trace.line, hits))
                },
                _ => ()
            };
        }

        for fn_line in fns.iter() {
            writeln!(file, "{}", fn_line)?;
        }

        writeln!(file, "FNF:{}", fns.len())?;

        for fnda_line in fnda {
            writeln!(file, "{}", fnda_line)?;
        }

        for da_line in da {
            writeln!(file, "{}", da_line)?;
        }

        writeln!(file, "end_of_record")?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Emulates virtual and hardware devices.

extern crate byteorder;
extern crate libc;

extern crate net_sys;
extern crate net_util;
#[macro_use]
extern crate sys_util;
extern crate virtio_sys;

mod bus;
mod i8042;
mod serial;

pub mod virtio;

pub use self::bus::{Bus, BusDevice};
pub use self::i8042::I8042Device;
pub use self::serial::Serial;
<commit_msg>devices/src/lib.rs: added EpollHandler trait<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Emulates virtual and hardware devices.

extern crate byteorder;
extern crate libc;

extern crate net_sys;
extern crate net_util;
#[macro_use]
extern crate sys_util;
extern crate virtio_sys;

mod bus;
mod i8042;
mod serial;

pub mod virtio;

pub use self::bus::{Bus, BusDevice};
pub use self::i8042::I8042Device;
pub use self::serial::Serial;

pub type DeviceEventT = u16;

pub trait EpollHandler : Send {
    fn handle_event(&mut self, device_event: DeviceEventT, event_flags: u32);
}
<|endoftext|>


<commit_before>/*! Thread-safe FitsFile struct */

use crate::errors::Result;
use crate::fitsfile::FitsFile;
use std::sync::{Arc, Mutex, MutexGuard};

/** Thread-safe [`FitsFile`][fits-file] representation.

This struct wraps an `Arc<Mutex<FitsFile>>` and implements `Send`.

To get a [`ThreadsafeFitsfile`][threadsafe-fitsfile] from a [`FitsFile`][fits-file], call the
[`threadsafe`][fits-file-threadsafe] method.

[fits-file]: ../fitsfile/struct.FitsFile.html
[threadsafe-fitsfile]: struct.ThreadsafeFitsFile.html
[fits-file-threadsafe]: ../fitsfile/struct.FitsFile.html#method.threadsafe
*/
#[derive(Clone)]
pub struct ThreadsafeFitsFile(Arc<Mutex<FitsFile>>);

/* Ensure that the new struct is safe to send to other threads */
unsafe impl Send for ThreadsafeFitsFile {}

impl FitsFile {
    /**
    Create a threadsafe [`ThreadsafeFitsFile`][threadsafe-fitsfile] copy of the current
    [`FitsFile`][fits-file].

    [threadsafe-fitsfile]: struct.ThreadsafeFitsFile.html
    [fits-file]: ../fitsfile/struct.FitsFile.html
     */
    pub fn threadsafe(self) -> ThreadsafeFitsFile {
        ThreadsafeFitsFile(Arc::new(Mutex::new(self)))
    }
}

impl ThreadsafeFitsFile {
    /**
    Lock the underlying mutex to return exclusive access to the FitsFile.
    */
    pub fn lock<'a>(&'a self) -> Result<MutexGuard<'a, FitsFile>> {
        self.0.lock().map_err(From::from)
    }
}

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

    #[test]
    fn test_using_other_threads() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let f = f.threadsafe();

        /* Spawn loads of threads... */
        let mut handles = Vec::new();
        for i in 0..10_000 {
            let f1 = f.clone();
            let handle = thread::spawn(move || {
                /* Get the underlyng fits file back */
                let mut t = f1.lock().unwrap();

                /* Fetch a different HDU per thread */
                let hdu_num = i % 2;
                let _hdu = t.hdu(hdu_num).unwrap();
            });
            handles.push(handle);
        }

        /* Wait for all of the threads to finish */
        for handle in handles {
            handle.join().unwrap();
        }
    }
}
<commit_msg>Fix clippy warning<commit_after>/*! Thread-safe FitsFile struct */

use crate::errors::Result;
use crate::fitsfile::FitsFile;
use std::sync::{Arc, Mutex, MutexGuard};

/** Thread-safe [`FitsFile`][fits-file] representation.

This struct wraps an `Arc<Mutex<FitsFile>>` and implements `Send`.

To get a [`ThreadsafeFitsfile`][threadsafe-fitsfile] from a [`FitsFile`][fits-file], call the
[`threadsafe`][fits-file-threadsafe] method.

[fits-file]: ../fitsfile/struct.FitsFile.html
[threadsafe-fitsfile]: struct.ThreadsafeFitsFile.html
[fits-file-threadsafe]: ../fitsfile/struct.FitsFile.html#method.threadsafe
*/
#[derive(Clone)]
pub struct ThreadsafeFitsFile(Arc<Mutex<FitsFile>>);

/* Ensure that the new struct is safe to send to other threads */
unsafe impl Send for ThreadsafeFitsFile {}

impl FitsFile {
    /**
    Create a threadsafe [`ThreadsafeFitsFile`][threadsafe-fitsfile] copy of the current
    [`FitsFile`][fits-file].

    [threadsafe-fitsfile]: struct.ThreadsafeFitsFile.html
    [fits-file]: ../fitsfile/struct.FitsFile.html
     */
    pub fn threadsafe(self) -> ThreadsafeFitsFile {
        ThreadsafeFitsFile(Arc::new(Mutex::new(self)))
    }
}

impl ThreadsafeFitsFile {
    /**
    Lock the underlying mutex to return exclusive access to the FitsFile.
    */
    pub fn lock(&self) -> Result<MutexGuard<'_, FitsFile>> {
        self.0.lock().map_err(From::from)
    }
}

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

    #[test]
    fn test_using_other_threads() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let f = f.threadsafe();

        /* Spawn loads of threads... */
        let mut handles = Vec::new();
        for i in 0..10_000 {
            let f1 = f.clone();
            let handle = thread::spawn(move || {
                /* Get the underlyng fits file back */
                let mut t = f1.lock().unwrap();

                /* Fetch a different HDU per thread */
                let hdu_num = i % 2;
                let _hdu = t.hdu(hdu_num).unwrap();
            });
            handles.push(handle);
        }

        /* Wait for all of the threads to finish */
        for handle in handles {
            handle.join().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_int, uint8_t, uint32_t};

    //SDL_pixels.h
    #[repr(C)]
    pub struct SDL_Color {
        pub r: uint8_t,
        pub g: uint8_t,
        pub b: uint8_t,
        pub a: uint8_t,
    }

    #[repr(C)]
    pub struct SDL_Palette {
        pub ncolors: c_int,
        pub colors: *const SDL_Color,
        pub version: uint32_t,
        pub refcount: c_int
    }

    #[allow(non_snake_case)]
    #[repr(C)]
    pub struct SDL_PixelFormat {
        pub format: SDL_PixelFormatFlag,
        pub palette: *const SDL_Palette,
        pub BitsPerPixel: uint8_t,
        pub BytesPerPixel: uint8_t,
        pub padding: [uint8_t, ..2],
        pub Rmask: uint8_t,
        pub Gmask: uint8_t,
        pub Bmask: uint8_t,
        pub Amask: uint8_t,
        pub Rloss: uint8_t,
        pub Gloss: uint8_t,
        pub Bloss: uint8_t,
        pub Aloss: uint8_t,
        pub Rshift: uint8_t,
        pub Gshift: uint8_t,
        pub Bshift: uint8_t,
        pub Ashift: uint8_t,
        pub refcount: c_int,
        pub next: *const SDL_PixelFormat
    }

    pub type SDL_PixelFormatFlag = uint32_t;
    pub const SDL_PIXELFORMAT_UNKNOWN: SDL_PixelFormatFlag = 0x0;
    pub const SDL_PIXELFORMAT_INDEX1LSB: SDL_PixelFormatFlag = 0x11100100;
    pub const SDL_PIXELFORMAT_INDEX1MSB: SDL_PixelFormatFlag = 0x11200100;
    pub const SDL_PIXELFORMAT_INDEX4LSB: SDL_PixelFormatFlag = 0x12100400;
    pub const SDL_PIXELFORMAT_INDEX4MSB: SDL_PixelFormatFlag = 0x12200400;
    pub const SDL_PIXELFORMAT_INDEX8: SDL_PixelFormatFlag = 0x13000801;
    pub const SDL_PIXELFORMAT_RGB332: SDL_PixelFormatFlag = 0x14110801;
    pub const SDL_PIXELFORMAT_RGB444: SDL_PixelFormatFlag = 0x15120c02;
    pub const SDL_PIXELFORMAT_RGB555: SDL_PixelFormatFlag = 0x15130f02;
    pub const SDL_PIXELFORMAT_BGR555: SDL_PixelFormatFlag = 0x15530f02;
    pub const SDL_PIXELFORMAT_ARGB4444: SDL_PixelFormatFlag = 0x15321002;
    pub const SDL_PIXELFORMAT_RGBA4444: SDL_PixelFormatFlag = 0x15421002;
    pub const SDL_PIXELFORMAT_ABGR4444: SDL_PixelFormatFlag = 0x15721002;
    pub const SDL_PIXELFORMAT_BGRA4444: SDL_PixelFormatFlag = 0x15821002;
    pub const SDL_PIXELFORMAT_ARGB1555: SDL_PixelFormatFlag = 0x15331002;
    pub const SDL_PIXELFORMAT_RGBA5551: SDL_PixelFormatFlag = 0x15441002;
    pub const SDL_PIXELFORMAT_ABGR1555: SDL_PixelFormatFlag = 0x15731002;
    pub const SDL_PIXELFORMAT_BGRA5551: SDL_PixelFormatFlag = 0x15841002;
    pub const SDL_PIXELFORMAT_RGB565: SDL_PixelFormatFlag = 0x15151002;
    pub const SDL_PIXELFORMAT_BGR565: SDL_PixelFormatFlag = 0x15551002;
    pub const SDL_PIXELFORMAT_RGB24: SDL_PixelFormatFlag = 0x17101803;
    pub const SDL_PIXELFORMAT_BGR24: SDL_PixelFormatFlag = 0x17401803;
    pub const SDL_PIXELFORMAT_RGB888: SDL_PixelFormatFlag = 0x16161804;
    pub const SDL_PIXELFORMAT_RGBX8888: SDL_PixelFormatFlag = 0x16261804;
    pub const SDL_PIXELFORMAT_BGR888: SDL_PixelFormatFlag = 0x16561804;
    pub const SDL_PIXELFORMAT_BGRX8888: SDL_PixelFormatFlag = 0x16661804;
    pub const SDL_PIXELFORMAT_ARGB8888: SDL_PixelFormatFlag = 0x16362004;
    pub const SDL_PIXELFORMAT_RGBA8888: SDL_PixelFormatFlag = 0x16462004;
    pub const SDL_PIXELFORMAT_ABGR8888: SDL_PixelFormatFlag = 0x16762004;
    pub const SDL_PIXELFORMAT_BGRA8888: SDL_PixelFormatFlag = 0x16862004;
    pub const SDL_PIXELFORMAT_ARGB2101010: SDL_PixelFormatFlag = 0x16372004;
    pub const SDL_PIXELFORMAT_YV12: SDL_PixelFormatFlag = 0x32315659;
    pub const SDL_PIXELFORMAT_IYUV: SDL_PixelFormatFlag = 0x56555949;
    pub const SDL_PIXELFORMAT_YUY2: SDL_PixelFormatFlag = 0x32595559;
    pub const SDL_PIXELFORMAT_UYVY: SDL_PixelFormatFlag = 0x59565955;
    pub const SDL_PIXELFORMAT_YVYU: SDL_PixelFormatFlag = 0x55595659;

    extern "C" {
        pub fn SDL_GetRGB(pixel: uint32_t, format: *const SDL_PixelFormat, r: *const uint8_t, g: *const uint8_t, b: *const uint8_t);
        pub fn SDL_GetRGBA(pixel: uint32_t, format: *const SDL_PixelFormat, r: *const uint8_t, g: *const uint8_t, b: *const uint8_t, a: *const uint8_t);
        pub fn SDL_MapRGB(format: *const SDL_PixelFormat, r: uint8_t, g: uint8_t, b: uint8_t) -> uint32_t;
        pub fn SDL_MapRGBA(format: *const SDL_PixelFormat, r: uint8_t, g: uint8_t, b: uint8_t, a: uint8_t) -> uint32_t;
    }
}
#[deriving(PartialEq)] #[allow(raw_pointer_deriving)]
pub struct Palette {
    raw: *const ll::SDL_Palette
}

impl_raw_accessors!(Palette, *const ll::SDL_Palette)

#[deriving(PartialEq, Clone)]
pub enum Color {
    RGB(u8, u8, u8),
    RGBA(u8, u8, u8, u8)
}

impl Color {
    pub fn to_u32(&self, format: &PixelFormat) -> u32 {
        match self {
            &RGB(r, g, b) => {
                unsafe { ll::SDL_MapRGB(format.raw, r, g, b) }
            }
            &RGBA(r, g, b, a) => {
                unsafe { ll::SDL_MapRGBA(format.raw, r, g, b, a) }
            }
        }
    }

    pub fn from_u32(format: &PixelFormat, pixel: u32) -> Color {
        let r: u8 = 0;
        let g: u8 = 0;
        let b: u8 = 0;
        let a: u8 = 0;

        unsafe {
            ll::SDL_GetRGBA(pixel, format.raw, &r, &g, &b, &a)
        };
        RGBA(r, g, b, a)
    }

    pub fn get_rgb(&self) -> (u8, u8, u8) {
        match self {
            &RGB(r, g, b) => (r, g, b),
            &RGBA(r, g, b, a) => (r, g, b)
        }
    }
}

impl rand::Rand for Color {
    fn rand<R: rand::Rng>(rng: &mut R) -> Color {
        if rng.gen() { RGBA(rng.gen(), rng.gen(), rng.gen(), rng.gen()) }
        else { RGB(rng.gen(), rng.gen(), rng.gen()) }
    }
}

#[deriving(PartialEq)] #[allow(raw_pointer_deriving)]
pub struct PixelFormat {
    raw: *const ll::SDL_PixelFormat
}

impl_raw_accessors!(PixelFormat, *const ll::SDL_PixelFormat)
impl_raw_constructor!(PixelFormat -> PixelFormat (raw: *const ll::SDL_PixelFormat))

#[deriving(PartialEq, Show, FromPrimitive)]
pub enum PixelFormatFlag {
    Unknown = ll::SDL_PIXELFORMAT_UNKNOWN as int,
    Index1LSB = ll::SDL_PIXELFORMAT_INDEX1LSB as int,
    Index1MSB = ll::SDL_PIXELFORMAT_INDEX1MSB as int,
    Index4LSB = ll::SDL_PIXELFORMAT_INDEX4LSB as int,
    Index4MSB = ll::SDL_PIXELFORMAT_INDEX4MSB as int,
    Index8 = ll::SDL_PIXELFORMAT_INDEX8 as int,
    RGB332 = ll::SDL_PIXELFORMAT_RGB332 as int,
    RGB444 = ll::SDL_PIXELFORMAT_RGB444 as int,
    RGB555 = ll::SDL_PIXELFORMAT_RGB555 as int,
    BGR555 = ll::SDL_PIXELFORMAT_BGR555 as int,
    ARGB4444 = ll::SDL_PIXELFORMAT_ARGB4444 as int,
    RGBA4444 = ll::SDL_PIXELFORMAT_RGBA4444 as int,
    ABGR4444 = ll::SDL_PIXELFORMAT_ABGR4444 as int,
    BGRA4444 = ll::SDL_PIXELFORMAT_BGRA4444 as int,
    ARGB1555 = ll::SDL_PIXELFORMAT_ARGB1555 as int,
    RGBA5551 = ll::SDL_PIXELFORMAT_RGBA5551 as int,
    ABGR1555 = ll::SDL_PIXELFORMAT_ABGR1555 as int,
    BGRA5551 = ll::SDL_PIXELFORMAT_BGRA5551 as int,
    RGB565 = ll::SDL_PIXELFORMAT_RGB565 as int,
    BGR565 = ll::SDL_PIXELFORMAT_BGR565 as int,
    RGB24 = ll::SDL_PIXELFORMAT_RGB24 as int,
    BGR24 = ll::SDL_PIXELFORMAT_BGR24 as int,
    RGB888 = ll::SDL_PIXELFORMAT_RGB888 as int,
    RGBX8888 = ll::SDL_PIXELFORMAT_RGBX8888 as int,
    BGR888 = ll::SDL_PIXELFORMAT_BGR888 as int,
    BGRX8888 = ll::SDL_PIXELFORMAT_BGRX8888 as int,
    ARGB8888 = ll::SDL_PIXELFORMAT_ARGB8888 as int,
    RGBA8888 = ll::SDL_PIXELFORMAT_RGBA8888 as int,
    ABGR8888 = ll::SDL_PIXELFORMAT_ABGR8888 as int,
    BGRA8888 = ll::SDL_PIXELFORMAT_BGRA8888 as int,
    ARGB2101010 = ll::SDL_PIXELFORMAT_ARGB2101010 as int,
    YV12 = ll::SDL_PIXELFORMAT_YV12 as int,
    IYUV = ll::SDL_PIXELFORMAT_IYUV as int,
    YUY2 = ll::SDL_PIXELFORMAT_YUY2 as int,
    UYVY = ll::SDL_PIXELFORMAT_UYVY as int,
    YVYU = ll::SDL_PIXELFORMAT_YVYU as int
}

impl PixelFormatFlag {
    pub fn byte_size_of_pixels(&self, num_of_pixels: uint) -> uint {
        match *self {
            RGB332
                => num_of_pixels * 1,
            RGB444 | RGB555 | BGR555 | ARGB4444 | RGBA4444 | ABGR4444 |
            BGRA4444 | ARGB1555 | RGBA5551 | ABGR1555 | BGRA5551 | RGB565 |
            BGR565
                => num_of_pixels * 2,
            RGB24 | BGR24
                => num_of_pixels * 3,
            RGB888 | RGBX8888 | BGR888 | BGRX8888 | ARGB8888 | RGBA8888 |
            ABGR8888 | BGRA8888 | ARGB2101010
                => num_of_pixels * 4,
            // YUV formats
            // FIXME: rounding error here?
            YV12 | IYUV
                => num_of_pixels / 2 * 3,
            YUY2 | UYVY | YVYU
                => num_of_pixels * 2,
            // Unsupported formats
            Index8
                => num_of_pixels * 1,
            Unknown | Index1LSB | Index1MSB | Index4LSB | Index4MSB
                => fail!("not supported format: {}", *self),
        }
    }

    pub fn byte_size_per_pixel(&self) -> uint {
        match *self {
            RGB332
                => 1,
            RGB444 | RGB555 | BGR555 | ARGB4444 | RGBA4444 | ABGR4444 |
            BGRA4444 | ARGB1555 | RGBA5551 | ABGR1555 | BGRA5551 | RGB565 |
            BGR565
                => 2,
            RGB24 | BGR24
                => 3,
            RGB888 | RGBX8888 | BGR888 | BGRX8888 | ARGB8888 | RGBA8888 |
            ABGR8888 | BGRA8888 | ARGB2101010
                => 4,
            // YUV formats
            YV12 | IYUV
                => 2,
            YUY2 | UYVY | YVYU
                => 2,
            // Unsupported formats
            Index8
                => 1,
            Unknown | Index1LSB | Index1MSB | Index4LSB | Index4MSB
                => fail!("not supported format: {}", *self),
        }
    }
}
<commit_msg>replace a to _ to avoid warning<commit_after>extern crate rand;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_int, uint8_t, uint32_t};

    //SDL_pixels.h
    #[repr(C)]
    pub struct SDL_Color {
        pub r: uint8_t,
        pub g: uint8_t,
        pub b: uint8_t,
        pub a: uint8_t,
    }

    #[repr(C)]
    pub struct SDL_Palette {
        pub ncolors: c_int,
        pub colors: *const SDL_Color,
        pub version: uint32_t,
        pub refcount: c_int
    }

    #[allow(non_snake_case)]
    #[repr(C)]
    pub struct SDL_PixelFormat {
        pub format: SDL_PixelFormatFlag,
        pub palette: *const SDL_Palette,
        pub BitsPerPixel: uint8_t,
        pub BytesPerPixel: uint8_t,
        pub padding: [uint8_t, ..2],
        pub Rmask: uint8_t,
        pub Gmask: uint8_t,
        pub Bmask: uint8_t,
        pub Amask: uint8_t,
        pub Rloss: uint8_t,
        pub Gloss: uint8_t,
        pub Bloss: uint8_t,
        pub Aloss: uint8_t,
        pub Rshift: uint8_t,
        pub Gshift: uint8_t,
        pub Bshift: uint8_t,
        pub Ashift: uint8_t,
        pub refcount: c_int,
        pub next: *const SDL_PixelFormat
    }

    pub type SDL_PixelFormatFlag = uint32_t;
    pub const SDL_PIXELFORMAT_UNKNOWN: SDL_PixelFormatFlag = 0x0;
    pub const SDL_PIXELFORMAT_INDEX1LSB: SDL_PixelFormatFlag = 0x11100100;
    pub const SDL_PIXELFORMAT_INDEX1MSB: SDL_PixelFormatFlag = 0x11200100;
    pub const SDL_PIXELFORMAT_INDEX4LSB: SDL_PixelFormatFlag = 0x12100400;
    pub const SDL_PIXELFORMAT_INDEX4MSB: SDL_PixelFormatFlag = 0x12200400;
    pub const SDL_PIXELFORMAT_INDEX8: SDL_PixelFormatFlag = 0x13000801;
    pub const SDL_PIXELFORMAT_RGB332: SDL_PixelFormatFlag = 0x14110801;
    pub const SDL_PIXELFORMAT_RGB444: SDL_PixelFormatFlag = 0x15120c02;
    pub const SDL_PIXELFORMAT_RGB555: SDL_PixelFormatFlag = 0x15130f02;
    pub const SDL_PIXELFORMAT_BGR555: SDL_PixelFormatFlag = 0x15530f02;
    pub const SDL_PIXELFORMAT_ARGB4444: SDL_PixelFormatFlag = 0x15321002;
    pub const SDL_PIXELFORMAT_RGBA4444: SDL_PixelFormatFlag = 0x15421002;
    pub const SDL_PIXELFORMAT_ABGR4444: SDL_PixelFormatFlag = 0x15721002;
    pub const SDL_PIXELFORMAT_BGRA4444: SDL_PixelFormatFlag = 0x15821002;
    pub const SDL_PIXELFORMAT_ARGB1555: SDL_PixelFormatFlag = 0x15331002;
    pub const SDL_PIXELFORMAT_RGBA5551: SDL_PixelFormatFlag = 0x15441002;
    pub const SDL_PIXELFORMAT_ABGR1555: SDL_PixelFormatFlag = 0x15731002;
    pub const SDL_PIXELFORMAT_BGRA5551: SDL_PixelFormatFlag = 0x15841002;
    pub const SDL_PIXELFORMAT_RGB565: SDL_PixelFormatFlag = 0x15151002;
    pub const SDL_PIXELFORMAT_BGR565: SDL_PixelFormatFlag = 0x15551002;
    pub const SDL_PIXELFORMAT_RGB24: SDL_PixelFormatFlag = 0x17101803;
    pub const SDL_PIXELFORMAT_BGR24: SDL_PixelFormatFlag = 0x17401803;
    pub const SDL_PIXELFORMAT_RGB888: SDL_PixelFormatFlag = 0x16161804;
    pub const SDL_PIXELFORMAT_RGBX8888: SDL_PixelFormatFlag = 0x16261804;
    pub const SDL_PIXELFORMAT_BGR888: SDL_PixelFormatFlag = 0x16561804;
    pub const SDL_PIXELFORMAT_BGRX8888: SDL_PixelFormatFlag = 0x16661804;
    pub const SDL_PIXELFORMAT_ARGB8888: SDL_PixelFormatFlag = 0x16362004;
    pub const SDL_PIXELFORMAT_RGBA8888: SDL_PixelFormatFlag = 0x16462004;
    pub const SDL_PIXELFORMAT_ABGR8888: SDL_PixelFormatFlag = 0x16762004;
    pub const SDL_PIXELFORMAT_BGRA8888: SDL_PixelFormatFlag = 0x16862004;
    pub const SDL_PIXELFORMAT_ARGB2101010: SDL_PixelFormatFlag = 0x16372004;
    pub const SDL_PIXELFORMAT_YV12: SDL_PixelFormatFlag = 0x32315659;
    pub const SDL_PIXELFORMAT_IYUV: SDL_PixelFormatFlag = 0x56555949;
    pub const SDL_PIXELFORMAT_YUY2: SDL_PixelFormatFlag = 0x32595559;
    pub const SDL_PIXELFORMAT_UYVY: SDL_PixelFormatFlag = 0x59565955;
    pub const SDL_PIXELFORMAT_YVYU: SDL_PixelFormatFlag = 0x55595659;

    extern "C" {
        pub fn SDL_GetRGB(pixel: uint32_t, format: *const SDL_PixelFormat, r: *const uint8_t, g: *const uint8_t, b: *const uint8_t);
        pub fn SDL_GetRGBA(pixel: uint32_t, format: *const SDL_PixelFormat, r: *const uint8_t, g: *const uint8_t, b: *const uint8_t, a: *const uint8_t);
        pub fn SDL_MapRGB(format: *const SDL_PixelFormat, r: uint8_t, g: uint8_t, b: uint8_t) -> uint32_t;
        pub fn SDL_MapRGBA(format: *const SDL_PixelFormat, r: uint8_t, g: uint8_t, b: uint8_t, a: uint8_t) -> uint32_t;
    }
}
#[deriving(PartialEq)] #[allow(raw_pointer_deriving)]
pub struct Palette {
    raw: *const ll::SDL_Palette
}

impl_raw_accessors!(Palette, *const ll::SDL_Palette)

#[deriving(PartialEq, Clone)]
pub enum Color {
    RGB(u8, u8, u8),
    RGBA(u8, u8, u8, u8)
}

impl Color {
    pub fn to_u32(&self, format: &PixelFormat) -> u32 {
        match self {
            &RGB(r, g, b) => {
                unsafe { ll::SDL_MapRGB(format.raw, r, g, b) }
            }
            &RGBA(r, g, b, a) => {
                unsafe { ll::SDL_MapRGBA(format.raw, r, g, b, a) }
            }
        }
    }

    pub fn from_u32(format: &PixelFormat, pixel: u32) -> Color {
        let r: u8 = 0;
        let g: u8 = 0;
        let b: u8 = 0;
        let a: u8 = 0;

        unsafe {
            ll::SDL_GetRGBA(pixel, format.raw, &r, &g, &b, &a)
        };
        RGBA(r, g, b, a)
    }

    pub fn get_rgb(&self) -> (u8, u8, u8) {
        match self {
            &RGB(r, g, b) => (r, g, b),
            &RGBA(r, g, b, _) => (r, g, b)
        }
    }
}

impl rand::Rand for Color {
    fn rand<R: rand::Rng>(rng: &mut R) -> Color {
        if rng.gen() { RGBA(rng.gen(), rng.gen(), rng.gen(), rng.gen()) }
        else { RGB(rng.gen(), rng.gen(), rng.gen()) }
    }
}

#[deriving(PartialEq)] #[allow(raw_pointer_deriving)]
pub struct PixelFormat {
    raw: *const ll::SDL_PixelFormat
}

impl_raw_accessors!(PixelFormat, *const ll::SDL_PixelFormat)
impl_raw_constructor!(PixelFormat -> PixelFormat (raw: *const ll::SDL_PixelFormat))

#[deriving(PartialEq, Show, FromPrimitive)]
pub enum PixelFormatFlag {
    Unknown = ll::SDL_PIXELFORMAT_UNKNOWN as int,
    Index1LSB = ll::SDL_PIXELFORMAT_INDEX1LSB as int,
    Index1MSB = ll::SDL_PIXELFORMAT_INDEX1MSB as int,
    Index4LSB = ll::SDL_PIXELFORMAT_INDEX4LSB as int,
    Index4MSB = ll::SDL_PIXELFORMAT_INDEX4MSB as int,
    Index8 = ll::SDL_PIXELFORMAT_INDEX8 as int,
    RGB332 = ll::SDL_PIXELFORMAT_RGB332 as int,
    RGB444 = ll::SDL_PIXELFORMAT_RGB444 as int,
    RGB555 = ll::SDL_PIXELFORMAT_RGB555 as int,
    BGR555 = ll::SDL_PIXELFORMAT_BGR555 as int,
    ARGB4444 = ll::SDL_PIXELFORMAT_ARGB4444 as int,
    RGBA4444 = ll::SDL_PIXELFORMAT_RGBA4444 as int,
    ABGR4444 = ll::SDL_PIXELFORMAT_ABGR4444 as int,
    BGRA4444 = ll::SDL_PIXELFORMAT_BGRA4444 as int,
    ARGB1555 = ll::SDL_PIXELFORMAT_ARGB1555 as int,
    RGBA5551 = ll::SDL_PIXELFORMAT_RGBA5551 as int,
    ABGR1555 = ll::SDL_PIXELFORMAT_ABGR1555 as int,
    BGRA5551 = ll::SDL_PIXELFORMAT_BGRA5551 as int,
    RGB565 = ll::SDL_PIXELFORMAT_RGB565 as int,
    BGR565 = ll::SDL_PIXELFORMAT_BGR565 as int,
    RGB24 = ll::SDL_PIXELFORMAT_RGB24 as int,
    BGR24 = ll::SDL_PIXELFORMAT_BGR24 as int,
    RGB888 = ll::SDL_PIXELFORMAT_RGB888 as int,
    RGBX8888 = ll::SDL_PIXELFORMAT_RGBX8888 as int,
    BGR888 = ll::SDL_PIXELFORMAT_BGR888 as int,
    BGRX8888 = ll::SDL_PIXELFORMAT_BGRX8888 as int,
    ARGB8888 = ll::SDL_PIXELFORMAT_ARGB8888 as int,
    RGBA8888 = ll::SDL_PIXELFORMAT_RGBA8888 as int,
    ABGR8888 = ll::SDL_PIXELFORMAT_ABGR8888 as int,
    BGRA8888 = ll::SDL_PIXELFORMAT_BGRA8888 as int,
    ARGB2101010 = ll::SDL_PIXELFORMAT_ARGB2101010 as int,
    YV12 = ll::SDL_PIXELFORMAT_YV12 as int,
    IYUV = ll::SDL_PIXELFORMAT_IYUV as int,
    YUY2 = ll::SDL_PIXELFORMAT_YUY2 as int,
    UYVY = ll::SDL_PIXELFORMAT_UYVY as int,
    YVYU = ll::SDL_PIXELFORMAT_YVYU as int
}

impl PixelFormatFlag {
    pub fn byte_size_of_pixels(&self, num_of_pixels: uint) -> uint {
        match *self {
            RGB332
                => num_of_pixels * 1,
            RGB444 | RGB555 | BGR555 | ARGB4444 | RGBA4444 | ABGR4444 |
            BGRA4444 | ARGB1555 | RGBA5551 | ABGR1555 | BGRA5551 | RGB565 |
            BGR565
                => num_of_pixels * 2,
            RGB24 | BGR24
                => num_of_pixels * 3,
            RGB888 | RGBX8888 | BGR888 | BGRX8888 | ARGB8888 | RGBA8888 |
            ABGR8888 | BGRA8888 | ARGB2101010
                => num_of_pixels * 4,
            // YUV formats
            // FIXME: rounding error here?
            YV12 | IYUV
                => num_of_pixels / 2 * 3,
            YUY2 | UYVY | YVYU
                => num_of_pixels * 2,
            // Unsupported formats
            Index8
                => num_of_pixels * 1,
            Unknown | Index1LSB | Index1MSB | Index4LSB | Index4MSB
                => fail!("not supported format: {}", *self),
        }
    }

    pub fn byte_size_per_pixel(&self) -> uint {
        match *self {
            RGB332
                => 1,
            RGB444 | RGB555 | BGR555 | ARGB4444 | RGBA4444 | ABGR4444 |
            BGRA4444 | ARGB1555 | RGBA5551 | ABGR1555 | BGRA5551 | RGB565 |
            BGR565
                => 2,
            RGB24 | BGR24
                => 3,
            RGB888 | RGBX8888 | BGR888 | BGRX8888 | ARGB8888 | RGBA8888 |
            ABGR8888 | BGRA8888 | ARGB2101010
                => 4,
            // YUV formats
            YV12 | IYUV
                => 2,
            YUY2 | UYVY | YVYU
                => 2,
            // Unsupported formats
            Index8
                => 1,
            Unknown | Index1LSB | Index1MSB | Index4LSB | Index4MSB
                => fail!("not supported format: {}", *self),
        }
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        not(feature = "no_jemalloc"),
    ),
    global_allocator
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let merge_max = cas_max + args.flag_merge_prop;
    let scan_max = merge_max + args.flag_scan_prop;

    let bytes = |len| -> Vec<u8> {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes: [u8; std::mem::size_of::<usize>()] =
            unsafe { std::mem::transmute(i) };

        i_bytes.into_iter().cycle().take(len).cloned().collect()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, bytes(args.flag_val_len)).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old_k = bytes(args.flag_val_len);

                let old = if rng.gen::<bool>() {
                    Some(old_k.as_slice())
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    Some(bytes(args.flag_val_len))
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, bytes(args.flag_val_len)).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args().into_iter()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(200))
        .snapshot_after_ops(100_000_000_000)
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(!args.flag_burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<commit_msg>Use iter instead of into_iter to resolve array ambiguity in stress2<commit_after>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        not(feature = "no_jemalloc"),
    ),
    global_allocator
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let merge_max = cas_max + args.flag_merge_prop;
    let scan_max = merge_max + args.flag_scan_prop;

    let bytes = |len| -> Vec<u8> {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes: [u8; std::mem::size_of::<usize>()] =
            unsafe { std::mem::transmute(i) };

        i_bytes.iter().cycle().take(len).cloned().collect()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, bytes(args.flag_val_len)).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old_k = bytes(args.flag_val_len);

                let old = if rng.gen::<bool>() {
                    Some(old_k.as_slice())
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    Some(bytes(args.flag_val_len))
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, bytes(args.flag_val_len)).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args().into_iter()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(200))
        .snapshot_after_ops(100_000_000_000)
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(!args.flag_burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<|endoftext|>


<commit_before>//! This crate helps to create a Fractalide component
//!
//! It provides the macro `component` which takes the high level view of the component, and creates the code for the scheduler.
//!
//! It also declare the Trait Agent and the shared methods needed by every component and the scheduler.

extern crate capnp;

// TODO : Add method to remove components
use ports::{IPSender, IPReceiver};
use scheduler::Signal;
use result::Result;

/// Provide the generic functions of agents
///
/// These three functions are used by the scheduler
pub trait Agent {
    /// Return true if there is at least one input port
    fn is_input_ports(&self) -> bool;
    /// Connect output port
    fn connect(&mut self, port: &str, sender: IPSender) -> Result<()>;
    /// Connect array output port
    fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()>;
    /// Add input element
    fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()>;
    /// Run the method of the component, his personal logic
    fn run(&mut self) -> Result<Signal>;
}

/// The agent macro.
///
/// It helps to define a agent, by defining the input and output ports, if there is an option or an acc port, ...
///
/// Example :
///
/// ```rust,ignore
/// agent! {
///    inputs(input: any),
///    outputs(output: any),
///    option(generic_text),
///    fn run(&mut self) -> Result<Signal> {
///        // Receive an IP
///        let ip = try!(self.input.input.recv());
///
///        // Received an IP from the option port (a generic_text)
///        let opt = self.recv_opt();
///
///        // Get the capn'p reader
///        let reader: generic_text::Reader = try!(opt.read_schema());
///        // Print the option
///        println!("{}", try!(reader.get_text()));
///
///        // Send the received IP outside, but don't care about the success (drop on fail)
///        let _ = self.output.output.send(ip);
///
///        Ok(End)
///    }
/// }
/// ```
#[macro_export]
macro_rules! agent {
    (
        $( input($( $input_name:ident: $input_contract:ident ),*), )*
        $( inarr($( $input_a_name:ident: $input_a_contract:ident ),*), )*
        $( output($( $output_name:ident: $output_contract:ident ),*), )*
        $( outarr($( $output_a_name:ident: $output_a_contract:ident ),*), )*
        $( portal( $portal_type:ty => $portal_value:expr ), )*
        $( option($option:ident), )*
        $( accumulator($acc:ident ), )*
        fn run(&mut $arg:ident) -> Result<Signal> $fun:block
    )
        =>
    {
        use rustfbp::agent::Agent;

        use rustfbp::result;
        use rustfbp::result::Result;
        use rustfbp::scheduler::{CompMsg, Signal};
        use std::error::Error;

        use std::sync::mpsc::{Sender};
        use std::sync::mpsc::channel;

        use rustfbp::ports::{IP, IPSender, IPReceiver, OutputSend};

        #[allow(unused_imports)]
        use std::collections::HashMap;

        use capnp::serialize;
        use capnp::message;

        use std::io::{Read, Write};

        use rustfbp::scheduler::Signal::*;

        mod edge_capnp {
                include!("edge_capnp.rs");
        }

        use edge_capnp::*;

        impl ThisAgent {
            pub fn recv_option(&mut self) -> IP {
                self.try_recv_option();
                if self.option_ip.is_none() {
                    self.option_ip = self.ports.recv("option").ok();
                }
                match self.option_ip {
                    Some(ref ip) => ip.clone(),
                    None => unreachable!(),
                }
            }

            pub fn try_recv_option(&mut self) -> Option<IP> {
                loop {
                    match self.ports.try_recv("option") {
                        Err(_) => { break; },
                        Ok(ip) => { self.option_ip = Some(ip); }
                    };
                }
                self.option_ip.as_ref().map(|ip|{ ip.clone() })
            }
        }

        // simple and array

            fn get_ports(&mut self) -> &mut Ports {
                &mut self.ports
            }
        impl Agent for ThisAgent {

            fn is_input_ports(&self) -> bool {
                $(
                    if true || stringify!($input_field_name) == "" { return true; }
                )*
                $(
                    if true || stringify!($input_array_name) == "" { return true; }
                )*
                false
            }

            fn run(&mut $arg) -> Result<()> $fun

        }

        /* Global agent */

        #[allow(dead_code)]
        #[allow(non_camel_case_types)]
        pub struct ThisAgent {
            name: String,
            pub ports: Ports,
            pub option_ip: Option<IP>,
            $(
            pub portal: $portal_type ,
            )*
        }

        #[allow(dead_code)]
        pub fn new(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            let (ports, senders) = try!(Ports::new(name.clone(), sched,
                                   vec!["option".into(), "acc".into(), $( stringify!($input_field_name).to_string() ),*],
                                   vec![$( stringify!($input_array_name).to_string() ),*],
                                   vec!["acc".into(), $( stringify!($output_field_name).to_string() ),*],
                                   vec![$( stringify!($output_array_name).to_string() ),*],));

            // Put it together
            let comp = $name{
                name: name,
                ports: ports,
                option_ip: None,
                $(
                    portal: $portal_value,
                )*
            };
            Ok((Box::new(comp) as Box<Agent + Send>, senders))
        }

        #[no_mangle]
        pub extern fn create_agent(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            new(name, sched)
        }

        #[no_mangle]
        pub extern fn get_schema_input(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_field_name)=> Ok(stringify!($input_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_input_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_array_name) => Ok(stringify!($input_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_field_name)=> Ok(stringify!($output_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_array_name) => Ok(stringify!($output_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }
    }
}
<commit_msg>Agent: update option<commit_after>//! This crate helps to create a Fractalide component
//!
//! It provides the macro `component` which takes the high level view of the component, and creates the code for the scheduler.
//!
//! It also declare the Trait Agent and the shared methods needed by every component and the scheduler.

extern crate capnp;

// TODO : Add method to remove components
use ports::{IPSender, IPReceiver};
use scheduler::Signal;
use result::Result;

/// Provide the generic functions of agents
///
/// These three functions are used by the scheduler
pub trait Agent {
    /// Return true if there is at least one input port
    fn is_input_ports(&self) -> bool;
    /// Connect output port
    fn connect(&mut self, port: &str, sender: IPSender) -> Result<()>;
    /// Connect array output port
    fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()>;
    /// Add input element
    fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()>;
    /// Run the method of the component, his personal logic
    fn run(&mut self) -> Result<Signal>;
}

/// The agent macro.
///
/// It helps to define a agent, by defining the input and output ports, if there is an option or an acc port, ...
///
/// Example :
///
/// ```rust,ignore
/// agent! {
///    inputs(input: any),
///    outputs(output: any),
///    option(generic_text),
///    fn run(&mut self) -> Result<Signal> {
///        // Receive an IP
///        let ip = try!(self.input.input.recv());
///
///        // Received an IP from the option port (a generic_text)
///        let opt = self.recv_opt();
///
///        // Get the capn'p reader
///        let reader: generic_text::Reader = try!(opt.read_schema());
///        // Print the option
///        println!("{}", try!(reader.get_text()));
///
///        // Send the received IP outside, but don't care about the success (drop on fail)
///        let _ = self.output.output.send(ip);
///
///        Ok(End)
///    }
/// }
/// ```
#[macro_export]
macro_rules! agent {
    (
        $( input($( $input_name:ident: $input_contract:ident ),*), )*
        $( inarr($( $input_a_name:ident: $input_a_contract:ident ),*), )*
        $( output($( $output_name:ident: $output_contract:ident ),*), )*
        $( outarr($( $output_a_name:ident: $output_a_contract:ident ),*), )*
        $( portal( $portal_type:ty => $portal_value:expr ), )*
        $( option($option:ident), )*
        $( accumulator($acc:ident ), )*
        fn run(&mut $arg:ident) -> Result<Signal> $fun:block
    )
        =>
    {
        use rustfbp::agent::Agent;

        use rustfbp::result;
        use rustfbp::result::Result;
        use rustfbp::scheduler::{CompMsg, Signal};
        use std::error::Error;

        use std::sync::mpsc::{Sender};
        use std::sync::mpsc::channel;

        use rustfbp::ports::{IP, IPSender, IPReceiver, OutputSend};

        #[allow(unused_imports)]
        use std::collections::HashMap;

        use capnp::serialize;
        use capnp::message;

        use std::io::{Read, Write};

        use rustfbp::scheduler::Signal::*;

        mod edge_capnp {
                include!("edge_capnp.rs");
        }

        use edge_capnp::*;

        impl ThisAgent {
            $(
            fn dummy() {
                if stringify!($option) != "" {}
            }
            pub fn recv_option(&mut self) -> IP {
                self.try_recv_option();
                if self.option_ip.is_none() {
                    self.option_ip = self.input.option.recv().ok();
                }
                match self.option_ip {
                    Some(ref ip) => ip.clone(),
                    None => unreachable!(),
                }
            }

            pub fn try_recv_option(&mut self) -> Option<IP> {
                loop {
                    match self.input.option.try_recv() {
                        Err(_) => { break; },
                        Ok(ip) => { self.option_ip = Some(ip); }
                    };
                }
                self.option_ip.as_ref().map(|ip|{ ip.clone() })
            }
        }

        // simple and array

            fn get_ports(&mut self) -> &mut Ports {
                &mut self.ports
            }
        impl Agent for ThisAgent {

            fn is_input_ports(&self) -> bool {
                $(
                    if true || stringify!($input_field_name) == "" { return true; }
                )*
                $(
                    if true || stringify!($input_array_name) == "" { return true; }
                )*
                false
            }

            fn run(&mut $arg) -> Result<()> $fun

        }

        /* Global agent */

        #[allow(dead_code)]
        #[allow(non_camel_case_types)]
        pub struct ThisAgent {
            name: String,
            pub ports: Ports,
            pub option_ip: Option<IP>,
            $(
            pub portal: $portal_type ,
            )*
        }

        #[allow(dead_code)]
        pub fn new(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            let (ports, senders) = try!(Ports::new(name.clone(), sched,
                                   vec!["option".into(), "acc".into(), $( stringify!($input_field_name).to_string() ),*],
                                   vec![$( stringify!($input_array_name).to_string() ),*],
                                   vec!["acc".into(), $( stringify!($output_field_name).to_string() ),*],
                                   vec![$( stringify!($output_array_name).to_string() ),*],));

            // Put it together
            let comp = $name{
                name: name,
                ports: ports,
                option_ip: None,
                $(
                    portal: $portal_value,
                )*
            };
            Ok((Box::new(comp) as Box<Agent + Send>, senders))
        }

        #[no_mangle]
        pub extern fn create_agent(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            new(name, sched)
        }

        #[no_mangle]
        pub extern fn get_schema_input(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_field_name)=> Ok(stringify!($input_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_input_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_array_name) => Ok(stringify!($input_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_field_name)=> Ok(stringify!($output_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_array_name) => Ok(stringify!($output_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate serde;
extern crate serde_json;
extern crate valico;

use clap::{Arg, App};
use serde_json::{Value, from_str};
use valico::json_schema;

use std::io;
use std::io::Read;
use std::fs::File;
use std::path::Path;

fn main() {
    let args = App::new("Schema Validator")
        .about("Experiment in validating a JSON Schema using Valico")
        .arg(Arg::with_name("InputJson")
            .long("json")
            .short("j")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("InputSchema")
            .long("schema")
            .short("s")
            .takes_value(true)
            .required(true))
        .get_matches();

    let input_json_path = Path::new(args.value_of("InputJson").unwrap());
    let input_json_data = read_file(&input_json_path).unwrap();

    let input_schema_path = Path::new(args.value_of("InputSchema").unwrap());
    let input_schema_data = read_file(&input_schema_path).unwrap();

    let schema: Value = from_str(&input_schema_data).unwrap();
    let data: Value = from_str(&input_json_data).unwrap();
    let mut scope = json_schema::Scope::new();

    let schema_compiled = match scope.compile_and_return(schema.clone(), false) {
        Ok(schema) => schema,
        Err(err) => panic!("Error in schema {:?}", err)
    };

    let state = schema_compiled.validate(&data["data"]);

    println!("Is JSON Valid? {:?}", state.is_valid());
    if state.is_valid() == false {
        for err in state.errors {
            println!("");
            if err.get_detail().is_some() == true {
                println!("Where: {}\nWhat: {}\nWhy: {}", err.get_path(), err.get_title(), err.get_detail().unwrap());
            } else {
                println!("Where: {}\nWhat: {}", err.get_path(), err.get_title());
            }
        }
    }
}

fn read_file(input_file_path: &Path) -> Result<String, io::Error> {
    let mut contents = String::new();
    File::open(input_file_path)?.read_to_string(&mut contents)?;
    Ok(contents)
}<commit_msg>Replaced some unwraps with pattern matching an more useful error messaging in schema experiment. Also moved to using Serde from_reader instead of reading file manually.<commit_after>extern crate clap;
extern crate serde;
extern crate serde_json;
extern crate valico;

use clap::{Arg, App};
use serde_json::{Value, from_reader};
use valico::json_schema;

use std::io;
use std::fs::File;
use std::path::Path;

fn main() {
    let args = App::new("Schema Validator")
        .about("Experiment in validating a JSON Schema using Valico")
        .arg(Arg::with_name("InputJson")
            .long("json")
            .short("j")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("InputSchema")
            .long("schema")
            .short("s")
            .takes_value(true)
            .required(true))
        .get_matches();

    let input_schema_path = Path::new(args.value_of("InputSchema").unwrap());
    let input_json_path = Path::new(args.value_of("InputJson").unwrap());

    let schema: Value = match File::open(input_schema_path) {
        Ok(file) => match from_reader(file) {
            Ok(value) => value,
            Err(err) => panic!("Failed to deserialise schema: {}", err)
        },
        Err(err) => panic!("Failed to open schema for reading: {}", err)
    };

    let data: Value = match File::open(input_json_path) {
        Ok(file) => match from_reader(file) {
            Ok(value) => value,
            Err(err) => panic!("Failed to deserialise data: {}", err)
        },
        Err(err) => panic!("Failed to open data for reading: {}", err)
    };

    let mut scope = json_schema::Scope::new();

    let schema_compiled = match scope.compile_and_return(schema.clone(), false) {
        Ok(schema) => schema,
        Err(err) => panic!("Error in schema {:?}", err)
    };

    let state = schema_compiled.validate(&data["data"]);

    println!("Is JSON Valid? {:?}", state.is_valid());
    if state.is_valid() == false {
        for err in state.errors {
            println!("");
            if err.get_detail().is_some() == true {
                println!("Where: {}\nWhat: {}\nWhy: {}", err.get_path(), err.get_title(), err.get_detail().unwrap());
            } else {
                println!("Where: {}\nWhat: {}", err.get_path(), err.get_title());
            }
        }
    }
}<|endoftext|>


<commit_before>// Originally from https://github.com/rust-lang/crates.io/blob/master/src/s3/lib.rs
//#![deny(warnings)]

use std::ascii::AsciiExt;
use std::fmt;

use base64;
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;
use futures::{Future, Stream};
use hyper::{self, header};
use hyper::Method;
use hyper::client::{Client, Request, HttpConnector};
use hyper_tls::HttpsConnector;
use simples3::credential::*;
use time;
use tokio_core::reactor::Handle;

use errors::*;

#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
/// Whether or not to use SSL.
pub enum Ssl {
    /// Use SSL.
    Yes,
    /// Do not use SSL.
    No,
}

fn base_url(endpoint: &str, ssl: Ssl) -> String {
    format!("{}://{}/",
            match ssl {
                Ssl::Yes => "https",
                Ssl::No => "http",
            },
            endpoint)
}

fn hmac<D: Digest>(d: D, key: &[u8], data: &[u8]) -> Vec<u8> {
    let mut hmac = Hmac::new(d, key);
    hmac.input(data);
    hmac.result().code().iter().map(|b| *b).collect::<Vec<u8>>()
}

fn signature(string_to_sign: &str, signing_key: &str) -> String {
    let s = hmac(Sha1::new(), signing_key.as_bytes(), string_to_sign.as_bytes());
    base64::encode_config::<Vec<u8>>(&s, base64::STANDARD)
}

/// An S3 bucket.
pub struct Bucket {
    name: String,
    base_url: String,
    client: Client<HttpsConnector<HttpConnector>>,
}

impl fmt::Display for Bucket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Bucket(name={}, base_url={})", self.name, self.base_url)
    }
}

impl Bucket {
    pub fn new(name: &str, endpoint: &str, ssl: Ssl, handle: &Handle)
        -> Result<Bucket>
    {
        let base_url = base_url(&endpoint, ssl);
        Ok(Bucket {
            name: name.to_owned(),
            base_url: base_url,
            client: Client::configure()
                        .connector(HttpsConnector::new(1, handle)?)
                        .build(handle),
        })
    }

    pub fn get(&self, key: &str) -> SFuture<Vec<u8>> {
        let url = format!("{}{}", self.base_url, key);
        debug!("GET {}", url);
        let url2 = url.clone();
        Box::new(self.client.get(url.parse().unwrap()).chain_err(move || {
            format!("failed GET: {}", url)
        }).and_then(|res| {
            if res.status().is_success() {
                let content_length = res.headers().get::<header::ContentLength>()
                    .map(|&header::ContentLength(len)| len);
                Ok((res.body(), content_length))
            } else {
                Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
            }
        }).and_then(|(body, content_length)| {
            body.fold(Vec::new(), |mut body, chunk| {
                body.extend_from_slice(&chunk);
                Ok::<_, hyper::Error>(body)
            }).chain_err(|| {
                "failed to read HTTP body"
            }).and_then(move |bytes| {
                if let Some(len) = content_length {
                    if len != bytes.len() as u64 {
                        bail!(format!("Bad HTTP body size read: {}, expected {}", bytes.len(), len));
                    } else {
                        info!("Read {} bytes from {}", bytes.len(), url2);
                    }
                }
                Ok(bytes)
            })
        }))
    }

    pub fn put(&self, key: &str, content: Vec<u8>, creds: &AwsCredentials)
               -> SFuture<()> {
        let url = format!("{}{}", self.base_url, key);
        debug!("PUT {}", url);
        let mut request = Request::new(Method::Put, url.parse().unwrap());

        let content_type = "application/octet-stream";
        let date = time::now_utc().rfc822().to_string();
        let mut canonical_headers = String::new();
        let token = creds.token().as_ref().map(|s| s.as_str());
        // Keep the list of header values sorted!
        for (header, maybe_value) in vec![
            ("x-amz-security-token", token),
            ("x-amz-storage-class", Some("REDUCED_REDUNDANCY")),
            ] {
            if let Some(ref value) = maybe_value {
                request.headers_mut()
                       .set_raw(header, vec!(value.as_bytes().to_vec()));
                canonical_headers.push_str(format!("{}:{}\n", header.to_ascii_lowercase(), value).as_ref());
            }
        }
        let auth = self.auth("PUT", &date, key, "", &canonical_headers, content_type, creds);
        request.headers_mut().set_raw("Date", vec!(date.into_bytes()));
        request.headers_mut().set(header::ContentType(content_type.parse().unwrap()));
        request.headers_mut().set(header::ContentLength(content.len() as u64));
        request.headers_mut().set(header::CacheControl(vec![
            // Two weeks
            header::CacheDirective::MaxAge(1296000)
        ]));
        request.headers_mut().set_raw("Authorization", vec!(auth.into_bytes()));
        request.set_body(content);

        Box::new(self.client.request(request).then(|result| {
            match result {
                Ok(res) => {
                    if res.status().is_success() {
                        trace!("PUT succeeded");
                        Ok(())
                    } else {
                        trace!("PUT failed with HTTP status: {}", res.status());
                        Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
                    }
                }
                Err(e) => {
                    trace!("PUT failed with error: {:?}", e);
                    Err(e.into())
                }
            }
        }))
    }

    // http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
    fn auth(&self, verb: &str, date: &str, path: &str,
            md5: &str, headers: &str, content_type: &str, creds: &AwsCredentials) -> String {
        let string = format!("{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
                             verb = verb,
                             md5 = md5,
                             ty = content_type,
                             date = date,
                             headers = headers,
                             resource = format!("/{}/{}", self.name, path));
        let signature = signature(&string, creds.aws_secret_access_key());
        format!("AWS {}:{}", creds.aws_access_key_id(), signature)
    }
}
<commit_msg>Switch S3 storage to use standard storage instead of reduced redundancy. Fixes #167<commit_after>// Originally from https://github.com/rust-lang/crates.io/blob/master/src/s3/lib.rs
//#![deny(warnings)]

use std::ascii::AsciiExt;
use std::fmt;

use base64;
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;
use futures::{Future, Stream};
use hyper::{self, header};
use hyper::Method;
use hyper::client::{Client, Request, HttpConnector};
use hyper_tls::HttpsConnector;
use simples3::credential::*;
use time;
use tokio_core::reactor::Handle;

use errors::*;

#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
/// Whether or not to use SSL.
pub enum Ssl {
    /// Use SSL.
    Yes,
    /// Do not use SSL.
    No,
}

fn base_url(endpoint: &str, ssl: Ssl) -> String {
    format!("{}://{}/",
            match ssl {
                Ssl::Yes => "https",
                Ssl::No => "http",
            },
            endpoint)
}

fn hmac<D: Digest>(d: D, key: &[u8], data: &[u8]) -> Vec<u8> {
    let mut hmac = Hmac::new(d, key);
    hmac.input(data);
    hmac.result().code().iter().map(|b| *b).collect::<Vec<u8>>()
}

fn signature(string_to_sign: &str, signing_key: &str) -> String {
    let s = hmac(Sha1::new(), signing_key.as_bytes(), string_to_sign.as_bytes());
    base64::encode_config::<Vec<u8>>(&s, base64::STANDARD)
}

/// An S3 bucket.
pub struct Bucket {
    name: String,
    base_url: String,
    client: Client<HttpsConnector<HttpConnector>>,
}

impl fmt::Display for Bucket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Bucket(name={}, base_url={})", self.name, self.base_url)
    }
}

impl Bucket {
    pub fn new(name: &str, endpoint: &str, ssl: Ssl, handle: &Handle)
        -> Result<Bucket>
    {
        let base_url = base_url(&endpoint, ssl);
        Ok(Bucket {
            name: name.to_owned(),
            base_url: base_url,
            client: Client::configure()
                        .connector(HttpsConnector::new(1, handle)?)
                        .build(handle),
        })
    }

    pub fn get(&self, key: &str) -> SFuture<Vec<u8>> {
        let url = format!("{}{}", self.base_url, key);
        debug!("GET {}", url);
        let url2 = url.clone();
        Box::new(self.client.get(url.parse().unwrap()).chain_err(move || {
            format!("failed GET: {}", url)
        }).and_then(|res| {
            if res.status().is_success() {
                let content_length = res.headers().get::<header::ContentLength>()
                    .map(|&header::ContentLength(len)| len);
                Ok((res.body(), content_length))
            } else {
                Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
            }
        }).and_then(|(body, content_length)| {
            body.fold(Vec::new(), |mut body, chunk| {
                body.extend_from_slice(&chunk);
                Ok::<_, hyper::Error>(body)
            }).chain_err(|| {
                "failed to read HTTP body"
            }).and_then(move |bytes| {
                if let Some(len) = content_length {
                    if len != bytes.len() as u64 {
                        bail!(format!("Bad HTTP body size read: {}, expected {}", bytes.len(), len));
                    } else {
                        info!("Read {} bytes from {}", bytes.len(), url2);
                    }
                }
                Ok(bytes)
            })
        }))
    }

    pub fn put(&self, key: &str, content: Vec<u8>, creds: &AwsCredentials)
               -> SFuture<()> {
        let url = format!("{}{}", self.base_url, key);
        debug!("PUT {}", url);
        let mut request = Request::new(Method::Put, url.parse().unwrap());

        let content_type = "application/octet-stream";
        let date = time::now_utc().rfc822().to_string();
        let mut canonical_headers = String::new();
        let token = creds.token().as_ref().map(|s| s.as_str());
        // Keep the list of header values sorted!
        for (header, maybe_value) in vec![
            ("x-amz-security-token", token),
            ] {
            if let Some(ref value) = maybe_value {
                request.headers_mut()
                       .set_raw(header, vec!(value.as_bytes().to_vec()));
                canonical_headers.push_str(format!("{}:{}\n", header.to_ascii_lowercase(), value).as_ref());
            }
        }
        let auth = self.auth("PUT", &date, key, "", &canonical_headers, content_type, creds);
        request.headers_mut().set_raw("Date", vec!(date.into_bytes()));
        request.headers_mut().set(header::ContentType(content_type.parse().unwrap()));
        request.headers_mut().set(header::ContentLength(content.len() as u64));
        request.headers_mut().set(header::CacheControl(vec![
            // Two weeks
            header::CacheDirective::MaxAge(1296000)
        ]));
        request.headers_mut().set_raw("Authorization", vec!(auth.into_bytes()));
        request.set_body(content);

        Box::new(self.client.request(request).then(|result| {
            match result {
                Ok(res) => {
                    if res.status().is_success() {
                        trace!("PUT succeeded");
                        Ok(())
                    } else {
                        trace!("PUT failed with HTTP status: {}", res.status());
                        Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
                    }
                }
                Err(e) => {
                    trace!("PUT failed with error: {:?}", e);
                    Err(e.into())
                }
            }
        }))
    }

    // http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
    fn auth(&self, verb: &str, date: &str, path: &str,
            md5: &str, headers: &str, content_type: &str, creds: &AwsCredentials) -> String {
        let string = format!("{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
                             verb = verb,
                             md5 = md5,
                             ty = content_type,
                             date = date,
                             headers = headers,
                             resource = format!("/{}/{}", self.name, path));
        let signature = signature(&string, creds.aws_secret_access_key());
        format!("AWS {}:{}", creds.aws_access_key_id(), signature)
    }
}
<|endoftext|>