<commit_before>//! A build dependency for Cargo libraries to find system artifacts through the
//! `pkg-config` utility.
//!
//! This library will shell out to `pkg-config` as part of build scripts and
//! probe the system to determine how to link to a specified library. The
//! `Config` structure serves as a method of configuring how `pkg-config` is
//! invoked in a builder style.
//!
//! A number of environment variables are available to globally configure how
//! this crate will invoke `pkg-config`:
//!
//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config`
//!   will automatically be disabled for all cross compiles.
//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when
//!   probing for the library named `foo`.
//!
//! There are also a number of environment variables which can configure how a
//! library is linked to (dynamically vs statically). These variables control
//! whether the `--static` flag is passed. Note that this behavior can be
//! overridden by configuring explicitly on `Config`. The variables are checked
//! in the following order:
//!
//! * `FOO_STATIC` - pass `--static` for the library `foo`
//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo`
//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries
//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries
//!
//! After running `pkg-config` all appropriate Cargo metadata will be printed on
//! stdout if the search was successful.
//!
//! # Example
//!
//! Find the system library named `foo`.
//!
//! ```no_run
//! extern crate pkg_config;
//!
//! fn main() {
//!     pkg_config::find_library("foo").unwrap();
//! }
//! ```
//!
//! Configure how library `foo` is linked to.
//!
//! ```no_run
//! extern crate pkg_config;
//!
//! fn main() {
//!     pkg_config::Config::new().statik(true).find("foo").unwrap();
//! }
//! ```

#![doc(html_root_url = "http://alexcrichton.com/pkg-config-rs")]
#![cfg_attr(test, deny(warnings))]

use std::ascii::AsciiExt;
use std::env;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::str;

pub fn target_supported() -> bool {
    env::var("HOST") == env::var("TARGET") ||
        env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()
}

#[derive(Clone)]
pub struct Config {
    statik: Option<bool>,
    atleast_version: Option<String>,
}

#[derive(Debug)]
pub struct Library {
    pub libs: Vec<String>,
    pub link_paths: Vec<PathBuf>,
    pub frameworks: Vec<String>,
    pub framework_paths: Vec<PathBuf>,
    pub include_paths: Vec<PathBuf>,
    _priv: (),
}

/// Simple shortcut for using all default options for finding a library.
pub fn find_library(name: &str) -> Result<Library, String> {
    Config::new().find(name)
}

impl Config {
    /// Creates a new set of configuration options which are all initially set
    /// to "blank".
    pub fn new() -> Config {
        Config {
            statik: None,
            atleast_version: None,
        }
    }

    /// Indicate whether the `--static` flag should be passed.
    ///
    /// This will override the inference from environment variables described in
    /// the crate documentation.
    pub fn statik(&mut self, statik: bool) -> &mut Config {
        self.statik = Some(statik);
        self
    }

    /// Indicate that the library must be at least version `vers`.
    pub fn atleast_version(&mut self, vers: &str) -> &mut Config {
        self.atleast_version = Some(vers.to_string());
        self
    }

    /// Run `pkg-config` to find the library `name`.
    ///
    /// This will use all configuration previously set to specify how
    /// `pkg-config` is run.
    pub fn find(&self, name: &str) -> Result<Library, String> {
        if env::var_os(&format!("{}_NO_PKG_CONFIG", envify(name))).is_some() {
            return Err(format!("pkg-config requested to be aborted for {}", name))
        } else if !target_supported() {
            return Err("pkg-config doesn't handle cross compilation. Use \
                        PKG_CONFIG_ALLOW_CROSS=1 to override".to_string());
        }

        let mut cmd = Command::new("pkg-config");
        let statik = self.statik.unwrap_or(infer_static(name));
        if statik {
            cmd.arg("--static");
        }
        cmd.arg("--libs").arg("--cflags")
           .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
        match self.atleast_version {
            Some(ref v) => { cmd.arg(&format!("{} >= {}", name, v)); }
            None => { cmd.arg(name); }
        }
        let out = try!(cmd.output().map_err(|e| {
            format!("failed to run `{:?}`: {}", cmd, e)
        }));
        let stdout = str::from_utf8(&out.stdout).unwrap();
        let stderr = str::from_utf8(&out.stderr).unwrap();
        if !out.status.success() {
            let mut msg = format!("`{:?}` did not exit successfully: {}", cmd,
                                  out.status);
            if stdout.len() > 0 {
                msg.push_str("\n--- stdout\n");
                msg.push_str(stdout);
            }
            if stderr.len() > 0 {
                msg.push_str("\n--- stderr\n");
                msg.push_str(stderr);
            }
            return Err(msg)
        }

        let mut ret = Library {
            libs: Vec::new(),
            link_paths: Vec::new(),
            include_paths: Vec::new(),
            frameworks: Vec::new(),
            framework_paths: Vec::new(),
            _priv: (),
        };
        let mut dirs = Vec::new();
        let parts = stdout.split(' ').filter(|l| l.len() > 2)
                          .map(|arg| (&arg[0..2], &arg[2..]))
                          .collect::<Vec<_>>();
        for &(flag, val) in parts.iter() {
            if flag == "-L" {
                println!("cargo:rustc-link-search=native={}", val);
                dirs.push(PathBuf::from(val));
                ret.link_paths.push(PathBuf::from(val));
            } else if flag == "-F" {
                println!("cargo:rustc-link-search=framework={}", val);
                ret.framework_paths.push(PathBuf::from(val));
            } else if flag == "-I" {
                ret.include_paths.push(PathBuf::from(val));
            }
        }
        for &(flag, val) in parts.iter() {
            if flag == "-l" {
                ret.libs.push(val.to_string());
                if statik && !is_system_lib(val, &dirs) {
                    println!("cargo:rustc-link-lib=static={}", val);
                } else {
                    println!("cargo:rustc-link-lib={}", val);
                }
            }
        }
        let mut iter = stdout.split(' ');
        while let Some(part) = iter.next() {
            if part != "-framework" { continue }
            if let Some(lib) = iter.next() {
                println!("cargo:rustc-link-lib=framework={}", lib);
                ret.frameworks.push(lib.to_string());
            }
        }

        Ok(ret)
    }
}

fn infer_static(name: &str) -> bool {
    let name = envify(name);
    if env::var_os(&format!("{}_STATIC", name)).is_some() {
        true
    } else if env::var_os(&format!("{}_DYNAMIC", name)).is_some() {
        false
    } else if env::var_os("PKG_CONFIG_ALL_STATIC").is_some() {
        true
    } else if env::var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() {
        false
    } else {
        false
    }
}

fn envify(name: &str) -> String {
    name.chars().map(|c| c.to_ascii_uppercase()).map(|c| if c == '-' {'_'} else {c})
        .collect()
}

fn is_system_lib(name: &str, dirs: &[PathBuf]) -> bool {
    let libname = format!("lib{}.a", name);
    let root = Path::new("/usr");
    !dirs.iter().any(|d| {
        !d.starts_with(root) && fs::metadata(&d.join(&libname)).is_ok()
    })
}
<commit_msg>Add support for extra args to pkg-config<commit_after>//! A build dependency for Cargo libraries to find system artifacts through the
//! `pkg-config` utility.
//!
//! This library will shell out to `pkg-config` as part of build scripts and
//! probe the system to determine how to link to a specified library. The
//! `Config` structure serves as a method of configuring how `pkg-config` is
//! invoked in a builder style.
//!
//! A number of environment variables are available to globally configure how
//! this crate will invoke `pkg-config`:
//!
//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config`
//!   will automatically be disabled for all cross compiles.
//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when
//!   probing for the library named `foo`.
//!
//! There are also a number of environment variables which can configure how a
//! library is linked to (dynamically vs statically). These variables control
//! whether the `--static` flag is passed. Note that this behavior can be
//! overridden by configuring explicitly on `Config`. The variables are checked
//! in the following order:
//!
//! * `FOO_STATIC` - pass `--static` for the library `foo`
//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo`
//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries
//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries
//!
//! After running `pkg-config` all appropriate Cargo metadata will be printed on
//! stdout if the search was successful.
//!
//! # Example
//!
//! Find the system library named `foo`.
//!
//! ```no_run
//! extern crate pkg_config;
//!
//! fn main() {
//!     pkg_config::find_library("foo").unwrap();
//! }
//! ```
//!
//! Configure how library `foo` is linked to.
//!
//! ```no_run
//! extern crate pkg_config;
//!
//! fn main() {
//!     pkg_config::Config::new().statik(true).find("foo").unwrap();
//! }
//! ```

#![doc(html_root_url = "http://alexcrichton.com/pkg-config-rs")]
#![cfg_attr(test, deny(warnings))]

use std::ascii::AsciiExt;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::str;

pub fn target_supported() -> bool {
    env::var("HOST") == env::var("TARGET") ||
        env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()
}

#[derive(Clone)]
pub struct Config {
    statik: Option<bool>,
    atleast_version: Option<String>,
    extra_args: Vec<OsString>,
}

#[derive(Debug)]
pub struct Library {
    pub libs: Vec<String>,
    pub link_paths: Vec<PathBuf>,
    pub frameworks: Vec<String>,
    pub framework_paths: Vec<PathBuf>,
    pub include_paths: Vec<PathBuf>,
    _priv: (),
}

/// Simple shortcut for using all default options for finding a library.
pub fn find_library(name: &str) -> Result<Library, String> {
    Config::new().find(name)
}

impl Config {
    /// Creates a new set of configuration options which are all initially set
    /// to "blank".
    pub fn new() -> Config {
        Config {
            statik: None,
            atleast_version: None,
            extra_args: vec![],
        }
    }

    /// Indicate whether the `--static` flag should be passed.
    ///
    /// This will override the inference from environment variables described in
    /// the crate documentation.
    pub fn statik(&mut self, statik: bool) -> &mut Config {
        self.statik = Some(statik);
        self
    }

    /// Indicate that the library must be at least version `vers`.
    pub fn atleast_version(&mut self, vers: &str) -> &mut Config {
        self.atleast_version = Some(vers.to_string());
        self
    }

    /// Add an argument to pass to pkg-config.
    ///
    /// It's placed after all of the arguments generated by this library.
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Config {
        self.extra_args.push(arg.as_ref().to_os_string());
        self
    }

    /// Run `pkg-config` to find the library `name`.
    ///
    /// This will use all configuration previously set to specify how
    /// `pkg-config` is run.
    pub fn find(&self, name: &str) -> Result<Library, String> {
        if env::var_os(&format!("{}_NO_PKG_CONFIG", envify(name))).is_some() {
            return Err(format!("pkg-config requested to be aborted for {}", name))
        } else if !target_supported() {
            return Err("pkg-config doesn't handle cross compilation. Use \
                        PKG_CONFIG_ALLOW_CROSS=1 to override".to_string());
        }

        let mut cmd = Command::new("pkg-config");
        let statik = self.statik.unwrap_or(infer_static(name));
        if statik {
            cmd.arg("--static");
        }
        cmd.arg("--libs").arg("--cflags")
           .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
        match self.atleast_version {
            Some(ref v) => { cmd.arg(&format!("{} >= {}", name, v)); }
            None => { cmd.arg(name); }
        }
        cmd.args(&self.extra_args);
        let out = try!(cmd.output().map_err(|e| {
            format!("failed to run `{:?}`: {}", cmd, e)
        }));
        let stdout = str::from_utf8(&out.stdout).unwrap();
        let stderr = str::from_utf8(&out.stderr).unwrap();
        if !out.status.success() {
            let mut msg = format!("`{:?}` did not exit successfully: {}", cmd,
                                  out.status);
            if stdout.len() > 0 {
                msg.push_str("\n--- stdout\n");
                msg.push_str(stdout);
            }
            if stderr.len() > 0 {
                msg.push_str("\n--- stderr\n");
                msg.push_str(stderr);
            }
            return Err(msg)
        }

        let mut ret = Library {
            libs: Vec::new(),
            link_paths: Vec::new(),
            include_paths: Vec::new(),
            frameworks: Vec::new(),
            framework_paths: Vec::new(),
            _priv: (),
        };
        let mut dirs = Vec::new();
        let parts = stdout.split(' ').filter(|l| l.len() > 2)
                          .map(|arg| (&arg[0..2], &arg[2..]))
                          .collect::<Vec<_>>();
        for &(flag, val) in parts.iter() {
            if flag == "-L" {
                println!("cargo:rustc-link-search=native={}", val);
                dirs.push(PathBuf::from(val));
                ret.link_paths.push(PathBuf::from(val));
            } else if flag == "-F" {
                println!("cargo:rustc-link-search=framework={}", val);
                ret.framework_paths.push(PathBuf::from(val));
            } else if flag == "-I" {
                ret.include_paths.push(PathBuf::from(val));
            }
        }
        for &(flag, val) in parts.iter() {
            if flag == "-l" {
                ret.libs.push(val.to_string());
                if statik && !is_system_lib(val, &dirs) {
                    println!("cargo:rustc-link-lib=static={}", val);
                } else {
                    println!("cargo:rustc-link-lib={}", val);
                }
            }
        }
        let mut iter = stdout.split(' ');
        while let Some(part) = iter.next() {
            if part != "-framework" { continue }
            if let Some(lib) = iter.next() {
                println!("cargo:rustc-link-lib=framework={}", lib);
                ret.frameworks.push(lib.to_string());
            }
        }

        Ok(ret)
    }
}

fn infer_static(name: &str) -> bool {
    let name = envify(name);
    if env::var_os(&format!("{}_STATIC", name)).is_some() {
        true
    } else if env::var_os(&format!("{}_DYNAMIC", name)).is_some() {
        false
    } else if env::var_os("PKG_CONFIG_ALL_STATIC").is_some() {
        true
    } else if env::var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() {
        false
    } else {
        false
    }
}

fn envify(name: &str) -> String {
    name.chars().map(|c| c.to_ascii_uppercase()).map(|c| if c == '-' {'_'} else {c})
        .collect()
}

fn is_system_lib(name: &str, dirs: &[PathBuf]) -> bool {
    let libname = format!("lib{}.a", name);
    let root = Path::new("/usr");
    !dirs.iter().any(|d| {
        !d.starts_with(root) && fs::metadata(&d.join(&libname)).is_ok()
    })
}
<|endoftext|>


<commit_before>static DIVISOR_IS_ZERO: &'static str              = "Divisor is zero";
static DIVISOR_LARGER_THAN_DIVIDEND: &'static str = "Divisor is larger than the dividend";

pub trait SplitInto {
    fn split_into(&self, divisor: uint) -> Result<Vec<int>, &'static str>;
}

impl SplitInto for int {
    fn split_into(&self, divisor: uint) -> Result<Vec<int>, &'static str> {
        let dividend = *self;
        if divisor == 0                     { return Err(DIVISOR_IS_ZERO) };
        if dividend == 0                    { return Ok(Vec::from_elem(divisor,0i)) };
        if divisor > dividend.abs() as uint { return Err(DIVISOR_LARGER_THAN_DIVIDEND) }

        let quotient  = dividend / divisor as int;
        let remainder = dividend.abs() as uint % divisor;

        let mut parts: Vec<int> = Vec::from_elem(divisor, quotient);

        let adjustment = if dividend > 0 { 1i } else if dividend < 0 { -1i } else { 0i };

        for x in range(0, remainder as uint) {
            *parts.get_mut(x) = parts[x] + adjustment;
        }

        parts.reverse();
        return Ok(parts);
    }
}
<commit_msg>Redundant check removed<commit_after>static DIVISOR_IS_ZERO: &'static str              = "Divisor is zero";
static DIVISOR_LARGER_THAN_DIVIDEND: &'static str = "Divisor is larger than the dividend";

pub trait SplitInto {
    fn split_into(&self, divisor: uint) -> Result<Vec<int>, &'static str>;
}

impl SplitInto for int {
    fn split_into(&self, divisor: uint) -> Result<Vec<int>, &'static str> {
        let dividend = *self;
        if divisor == 0                     { return Err(DIVISOR_IS_ZERO) };
        if dividend == 0                    { return Ok(Vec::from_elem(divisor,0i)) };
        if divisor > dividend.abs() as uint { return Err(DIVISOR_LARGER_THAN_DIVIDEND) }

        let quotient  = dividend / divisor as int;
        let remainder = dividend.abs() as uint % divisor;

        let mut parts: Vec<int> = Vec::from_elem(divisor, quotient);

        let adjustment = if dividend > 0 { 1i } else { -1i };

        for x in range(0, remainder as uint) {
            *parts.get_mut(x) = parts[x] + adjustment;
        }

        parts.reverse();
        return Ok(parts);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate crc16;

use std::io::{self, Read, Write};
use std::convert::From;

// TODO: Send CAN byte after too many errors
// TODO: Handle CAN bytes while sending
// TODO: Implement Error for Error

const SOH: u8 = 0x01;
const STX: u8 = 0x02;
const EOT: u8 = 0x04;
const ACK: u8 = 0x06;
const NAK: u8 = 0x15;
const CAN: u8 = 0x18;
const CRC: u8 = 0x67;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    ExhaustedRetries,
    Canceled,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

#[derive(Copy, Clone, Debug)]
enum Checksum {
    Standard,
    CRC16,
}

#[derive(Copy, Clone, Debug)]
pub enum BlockLength {
    Standard = 128,
    OneK = 1024,
}

#[derive(Copy, Clone, Debug)]
pub struct Xmodem {
    pub max_errors: u32,
    pub pad_byte: u8,
    pub block_length: BlockLength,
    checksum_mode: Checksum,
    errors: u32,
}

impl Xmodem {
    pub fn new() -> Self {
        Xmodem {
            max_errors: 16,
            pad_byte: 0x1a,
            block_length: BlockLength::Standard,
            checksum_mode: Checksum::Standard,
            errors: 0,
        }
    }

    pub fn send<D: Read + Write, R: Read>(&mut self, dev: &mut D, stream: &mut R) -> Result<()> {
        self.errors = 0;

        debug!("Starting XMODEM transfer");
        try!(self.start_send(dev));
        debug!("First byte received. Sending stream.");
        try!(self.send_stream(dev, stream));
        debug!("Sending EOT");
        try!(self.finish_send(dev));

        Ok(())
    }

    pub fn start_send<D: Read + Write>(&mut self, dev: &mut D) -> Result<()> {
        let mut cancels = 0u32;
        loop {
            match try!(get_byte_timeout(dev)) {
                Some(c) => {
                    match c {
                        NAK => {
                            debug!("Standard checksum requested");
                            self.checksum_mode = Checksum::Standard;
                            return Ok(());
                        }
                        CRC => {
                            debug!("16-bit CRC requested");
                            self.checksum_mode = Checksum::CRC16;
                            return Ok(());
                        }
                        CAN => {
                            warn!("Cancel (CAN) byte received");
                            cancels += 1;
                        },
                        c => warn!("Unknown byte received at start of XMODEM transfer: {}", c),
                    }
                },
                None => warn!("Timed out waiting for start of XMODEM transfer."),
            }

            self.errors += 1;

            if cancels >= 2 {
                error!("Transmission canceled: received two cancel (CAN) bytes \
                        at start of XMODEM transfer");
                return Err(Error::Canceled);
            }

            if self.errors >= self.max_errors {
                error!("Exhausted max retries ({}) at start of XMODEM transfer.", self.max_errors);
                if let Err(err) = dev.write_all(&[CAN]) {
                    warn!("Error sending CAN byte: {}", err);
                }
                return Err(Error::ExhaustedRetries);
            }
        }
    }

    fn send_stream<D: Read + Write, R: Read>(&mut self, dev: &mut D, stream: &mut R) -> Result<()> {
        let mut block_num = 0u32;
        loop {
            let mut buff = vec![self.pad_byte; self.block_length as usize + 3];
            let n = try!(stream.read(&mut buff[3..]));
            if n == 0 {
                debug!("Reached EOF");
                return Ok(());
            }

            block_num += 1;
            buff[0] = match self.block_length {
                BlockLength::Standard => SOH,
                BlockLength::OneK => STX,
            };
            buff[1] = (block_num & 0xFF) as u8;
            buff[2] = 0xFF - buff[1];

            match self.checksum_mode {
                Checksum::Standard => {
                    let checksum = calc_checksum(&buff);
                    buff.push(checksum);
                },
                Checksum::CRC16 => {
                    let crc = calc_crc(&buff);
                    buff.push(((crc >> 8) & 0xFF) as u8);
                    buff.push((crc & 0xFF) as u8);
                }
            }

            debug!("Sending block {}", block_num);
            try!(dev.write_all(&buff));

            match try!(get_byte_timeout(dev)) {
                Some(c) => {
                    if c == ACK {
                        debug!("Received ACK for block {}", block_num);
                        continue
                    } else {
                        warn!("Expected ACK, got {}", c);
                    }
                    // TODO handle CAN bytes
                },
                None => warn!("Timeout waiting for ACK for block {}", block_num),
            }

            self.errors += 1;

            if self.errors >= self.max_errors {
                error!("Exhausted max retries ({}) while sending block {} in XMODEM transfer",
                       self.max_errors, block_num);
                return Err(Error::ExhaustedRetries);
            }
        }
    }

    fn finish_send<D: Read + Write>(&mut self, dev: &mut D) -> Result<()> {
        loop {
            try!(dev.write_all(&[EOT]));

            match try!(get_byte_timeout(dev)) {
                Some(c) => {
                    if c == ACK {
                        info!("XMODEM transmission successful");
                        return Ok(());
                    } else {
                        warn!("Expected ACK, got {}", c);
                    }
                },
                None => warn!("Timeout waiting for ACK for EOT"),
            }

            self.errors += 1;

            if self.errors >= self.max_errors {
                error!("Exhausted max retries ({}) while waiting for ACK for EOT", self.max_errors);
                return Err(Error::ExhaustedRetries);
            }
        }
    }
}

fn calc_checksum(data: &[u8]) -> u8 {
    data.iter().fold(0, |x, &y| x.wrapping_add(y))
}

fn calc_crc(data: &[u8]) -> u16 {
    crc16::State::<crc16::XMODEM>::calculate(data)
}

fn get_byte<R: Read>(reader: &mut R) -> std::io::Result<u8> {
    let mut buff = [0];
    try!(reader.read_exact(&mut buff));
    Ok(buff[0])
}

/// Turns timeout errors into `Ok(None)`
fn get_byte_timeout<R: Read>(reader: &mut R) -> std::io::Result<Option<u8>> {
    match get_byte(reader) {
        Ok(c) => Ok(Some(c)),
        Err(err) => {
            if err.kind() == io::ErrorKind::TimedOut {
                Ok(None)
            } else {
                Err(err)
            }
        }
    }
}
<commit_msg>Fixed incorrect CRC byte<commit_after>#[macro_use]
extern crate log;
extern crate crc16;

use std::io::{self, Read, Write};
use std::convert::From;

// TODO: Send CAN byte after too many errors
// TODO: Handle CAN bytes while sending
// TODO: Implement Error for Error

const SOH: u8 = 0x01;
const STX: u8 = 0x02;
const EOT: u8 = 0x04;
const ACK: u8 = 0x06;
const NAK: u8 = 0x15;
const CAN: u8 = 0x18;
const CRC: u8 = 0x43;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    ExhaustedRetries,
    Canceled,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

#[derive(Copy, Clone, Debug)]
enum Checksum {
    Standard,
    CRC16,
}

#[derive(Copy, Clone, Debug)]
pub enum BlockLength {
    Standard = 128,
    OneK = 1024,
}

#[derive(Copy, Clone, Debug)]
pub struct Xmodem {
    pub max_errors: u32,
    pub pad_byte: u8,
    pub block_length: BlockLength,
    checksum_mode: Checksum,
    errors: u32,
}

impl Xmodem {
    pub fn new() -> Self {
        Xmodem {
            max_errors: 16,
            pad_byte: 0x1a,
            block_length: BlockLength::Standard,
            checksum_mode: Checksum::Standard,
            errors: 0,
        }
    }

    pub fn send<D: Read + Write, R: Read>(&mut self, dev: &mut D, stream: &mut R) -> Result<()> {
        self.errors = 0;

        debug!("Starting XMODEM transfer");
        try!(self.start_send(dev));
        debug!("First byte received. Sending stream.");
        try!(self.send_stream(dev, stream));
        debug!("Sending EOT");
        try!(self.finish_send(dev));

        Ok(())
    }

    pub fn start_send<D: Read + Write>(&mut self, dev: &mut D) -> Result<()> {
        let mut cancels = 0u32;
        loop {
            match try!(get_byte_timeout(dev)) {
                Some(c) => {
                    match c {
                        NAK => {
                            debug!("Standard checksum requested");
                            self.checksum_mode = Checksum::Standard;
                            return Ok(());
                        }
                        CRC => {
                            debug!("16-bit CRC requested");
                            self.checksum_mode = Checksum::CRC16;
                            return Ok(());
                        }
                        CAN => {
                            warn!("Cancel (CAN) byte received");
                            cancels += 1;
                        },
                        c => warn!("Unknown byte received at start of XMODEM transfer: {}", c),
                    }
                },
                None => warn!("Timed out waiting for start of XMODEM transfer."),
            }

            self.errors += 1;

            if cancels >= 2 {
                error!("Transmission canceled: received two cancel (CAN) bytes \
                        at start of XMODEM transfer");
                return Err(Error::Canceled);
            }

            if self.errors >= self.max_errors {
                error!("Exhausted max retries ({}) at start of XMODEM transfer.", self.max_errors);
                if let Err(err) = dev.write_all(&[CAN]) {
                    warn!("Error sending CAN byte: {}", err);
                }
                return Err(Error::ExhaustedRetries);
            }
        }
    }

    fn send_stream<D: Read + Write, R: Read>(&mut self, dev: &mut D, stream: &mut R) -> Result<()> {
        let mut block_num = 0u32;
        loop {
            let mut buff = vec![self.pad_byte; self.block_length as usize + 3];
            let n = try!(stream.read(&mut buff[3..]));
            if n == 0 {
                debug!("Reached EOF");
                return Ok(());
            }

            block_num += 1;
            buff[0] = match self.block_length {
                BlockLength::Standard => SOH,
                BlockLength::OneK => STX,
            };
            buff[1] = (block_num & 0xFF) as u8;
            buff[2] = 0xFF - buff[1];

            match self.checksum_mode {
                Checksum::Standard => {
                    let checksum = calc_checksum(&buff);
                    buff.push(checksum);
                },
                Checksum::CRC16 => {
                    let crc = calc_crc(&buff);
                    buff.push(((crc >> 8) & 0xFF) as u8);
                    buff.push((crc & 0xFF) as u8);
                }
            }

            debug!("Sending block {}", block_num);
            try!(dev.write_all(&buff));

            match try!(get_byte_timeout(dev)) {
                Some(c) => {
                    if c == ACK {
                        debug!("Received ACK for block {}", block_num);
                        continue
                    } else {
                        warn!("Expected ACK, got {}", c);
                    }
                    // TODO handle CAN bytes
                },
                None => warn!("Timeout waiting for ACK for block {}", block_num),
            }

            self.errors += 1;

            if self.errors >= self.max_errors {
                error!("Exhausted max retries ({}) while sending block {} in XMODEM transfer",
                       self.max_errors, block_num);
                return Err(Error::ExhaustedRetries);
            }
        }
    }

    fn finish_send<D: Read + Write>(&mut self, dev: &mut D) -> Result<()> {
        loop {
            try!(dev.write_all(&[EOT]));

            match try!(get_byte_timeout(dev)) {
                Some(c) => {
                    if c == ACK {
                        info!("XMODEM transmission successful");
                        return Ok(());
                    } else {
                        warn!("Expected ACK, got {}", c);
                    }
                },
                None => warn!("Timeout waiting for ACK for EOT"),
            }

            self.errors += 1;

            if self.errors >= self.max_errors {
                error!("Exhausted max retries ({}) while waiting for ACK for EOT", self.max_errors);
                return Err(Error::ExhaustedRetries);
            }
        }
    }
}

fn calc_checksum(data: &[u8]) -> u8 {
    data.iter().fold(0, |x, &y| x.wrapping_add(y))
}

fn calc_crc(data: &[u8]) -> u16 {
    crc16::State::<crc16::XMODEM>::calculate(data)
}

fn get_byte<R: Read>(reader: &mut R) -> std::io::Result<u8> {
    let mut buff = [0];
    try!(reader.read_exact(&mut buff));
    Ok(buff[0])
}

/// Turns timeout errors into `Ok(None)`
fn get_byte_timeout<R: Read>(reader: &mut R) -> std::io::Result<Option<u8>> {
    match get_byte(reader) {
        Ok(c) => Ok(Some(c)),
        Err(err) => {
            if err.kind() == io::ErrorKind::TimedOut {
                Ok(None)
            } else {
                Err(err)
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(rust_2018_idioms, warnings)]
#![allow(
    clippy::needless_doctest_main,
    clippy::type_complexity,
    clippy::borrow_interior_mutable_const
)]
//! Actix web is a small, pragmatic, and extremely fast web framework
//! for Rust.
//!
//! ```rust,no_run
//! use actix_web::{web, App, Responder, HttpServer};
//!
//! async fn index(info: web::Path<(String, u32)>) -> impl Responder {
//!     format!("Hello {}! id:{}", info.0, info.1)
//! }
//!
//! #[actix_rt::main]
//! async fn main() -> std::io::Result<()> {
//!     HttpServer::new(|| App::new().service(
//!         web::resource("/{name}/{id}/index.html").to(index))
//!     )
//!         .bind("127.0.0.1:8080")?
//!         .run()
//!         .await
//! }
//! ```
//!
//! ## Documentation & community resources
//!
//! Besides the API documentation (which you are currently looking
//! at!), several other resources are available:
//!
//! * [User Guide](https://actix.rs/docs/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)
//!
//! To get started navigating the API documentation you may want to
//! consider looking at the following pages:
//!
//! * [App](struct.App.html): This struct represents an actix-web
//!   application and is used to configure routes and other common
//!   settings.
//!
//! * [HttpServer](struct.HttpServer.html): This struct
//!   represents an HTTP server instance and is used to instantiate and
//!   configure servers.
//!
//! * [web](web/index.html): This module
//!   provides essential helper functions and types for application registration.
//!
//! * [HttpRequest](struct.HttpRequest.html) and
//!   [HttpResponse](struct.HttpResponse.html): These structs
//!   represent HTTP requests and responses and expose various methods
//!   for inspecting, creating and otherwise utilizing them.
//!
//! ## Features
//!
//! * Supported *HTTP/1.x* and *HTTP/2.0* protocols
//! * Streaming and pipelining
//! * Keep-alive and slow requests handling
//! * `WebSockets` server/client
//! * Transparent content compression/decompression (br, gzip, deflate)
//! * Configurable request routing
//! * Multipart streams
//! * SSL support with OpenSSL or `native-tls`
//! * Middlewares (`Logger`, `Session`, `CORS`, `DefaultHeaders`)
//! * Supports [Actix actor framework](https://github.com/actix/actix)
//! * Supported Rust version: 1.39 or later
//!
//! ## Package feature
//!
//! * `client` - enables http client (default enabled)
//! * `compress` - enables content encoding compression support (default enabled)
//! * `openssl` - enables ssl support via `openssl` crate, supports `http/2`
//! * `rustls` - enables ssl support via `rustls` crate, supports `http/2`
//! * `secure-cookies` - enables secure cookies support, includes `ring` crate as
//!   dependency
#![allow(clippy::type_complexity, clippy::new_without_default)]

mod app;
mod app_service;
mod config;
mod data;
pub mod error;
mod extract;
pub mod guard;
mod handler;
mod info;
pub mod middleware;
mod request;
mod resource;
mod responder;
mod rmap;
mod route;
mod scope;
mod server;
mod service;
pub mod test;
mod types;
pub mod web;

#[doc(hidden)]
pub use actix_web_codegen::*;

// re-export for convenience
pub use actix_http::Response as HttpResponse;
pub use actix_http::{body, cookie, http, Error, HttpMessage, ResponseError, Result};

pub use crate::app::App;
pub use crate::extract::FromRequest;
pub use crate::request::HttpRequest;
pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::scope::Scope;
pub use crate::server::HttpServer;

pub mod dev {
    //! The `actix-web` prelude for library developers
    //!
    //! The purpose of this module is to alleviate imports of many common actix
    //! traits by adding a glob import to the top of actix heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use actix_web::dev::*;
    //! ```

    pub use crate::config::{AppConfig, AppService};
    #[doc(hidden)]
    pub use crate::handler::Factory;
    pub use crate::info::ConnectionInfo;
    pub use crate::rmap::ResourceMap;
    pub use crate::service::{
        HttpServiceFactory, ServiceRequest, ServiceResponse, WebService,
    };

    pub use crate::types::form::UrlEncoded;
    pub use crate::types::json::JsonBody;
    pub use crate::types::readlines::Readlines;

    pub use actix_http::body::{Body, BodySize, MessageBody, ResponseBody, SizedStream};
    #[cfg(feature = "compress")]
    pub use actix_http::encoding::Decoder as Decompress;
    pub use actix_http::ResponseBuilder as HttpResponseBuilder;
    pub use actix_http::{
        Extensions, Payload, PayloadStream, RequestHead, ResponseHead,
    };
    pub use actix_router::{Path, ResourceDef, ResourcePath, Url};
    pub use actix_server::Server;
    pub use actix_service::{Service, Transform};

    pub(crate) fn insert_slash(mut patterns: Vec<String>) -> Vec<String> {
        for path in &mut patterns {
            if !path.is_empty() && !path.starts_with('/') {
                path.insert(0, '/');
            };
        }
        patterns
    }

    use crate::http::header::ContentEncoding;
    use actix_http::{Response, ResponseBuilder};

    struct Enc(ContentEncoding);

    /// Helper trait that allows to set specific encoding for response.
    pub trait BodyEncoding {
        /// Get content encoding
        fn get_encoding(&self) -> Option<ContentEncoding>;

        /// Set content encoding
        fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self;
    }

    impl BodyEncoding for ResponseBuilder {
        fn get_encoding(&self) -> Option<ContentEncoding> {
            if let Some(ref enc) = self.extensions().get::<Enc>() {
                Some(enc.0)
            } else {
                None
            }
        }

        fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
            self.extensions_mut().insert(Enc(encoding));
            self
        }
    }

    impl<B> BodyEncoding for Response<B> {
        fn get_encoding(&self) -> Option<ContentEncoding> {
            if let Some(ref enc) = self.extensions().get::<Enc>() {
                Some(enc.0)
            } else {
                None
            }
        }

        fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
            self.extensions_mut().insert(Enc(encoding));
            self
        }
    }
}

pub mod client {
    //! An HTTP Client
    //!
    //! ```rust
    //! use actix_web::client::Client;
    //!
    //! #[actix_rt::main]
    //! async fn main() {
    //!    let mut client = Client::default();
    //!
    //!    // Create request builder and send request
    //!    let response = client.get("http://www.rust-lang.org")
    //!       .header("User-Agent", "Actix-web")
    //!       .send().await;                      // <- Send http request
    //!
    //!    println!("Response: {:?}", response);
    //! }
    //! ```
    pub use awc::error::{
        ConnectError, InvalidUrl, PayloadError, SendRequestError, WsClientError,
    };
    pub use awc::{
        test, Client, ClientBuilder, ClientRequest, ClientResponse, Connector,
    };
}
<commit_msg>Add dependencies to docs example (#1343)<commit_after>#![deny(rust_2018_idioms, warnings)]
#![allow(
    clippy::needless_doctest_main,
    clippy::type_complexity,
    clippy::borrow_interior_mutable_const
)]
//! Actix web is a small, pragmatic, and extremely fast web framework
//! for Rust.
//!
//! ## Example
//!
//! The `#[actix_rt::main]` macro in the example below is provided by the Actix runtime
//! crate, [`actix-rt`](https://crates.io/crates/actix-rt). You will need to include
//! `actix-rt` in your dependencies for it to run.
//!
//! ```rust,no_run
//! use actix_web::{web, App, Responder, HttpServer};
//!
//! async fn index(info: web::Path<(String, u32)>) -> impl Responder {
//!     format!("Hello {}! id:{}", info.0, info.1)
//! }
//!
//! #[actix_rt::main]
//! async fn main() -> std::io::Result<()> {
//!     HttpServer::new(|| App::new().service(
//!         web::resource("/{name}/{id}/index.html").to(index))
//!     )
//!         .bind("127.0.0.1:8080")?
//!         .run()
//!         .await
//! }
//! ```
//!
//! ## Documentation & community resources
//!
//! Besides the API documentation (which you are currently looking
//! at!), several other resources are available:
//!
//! * [User Guide](https://actix.rs/docs/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)
//!
//! To get started navigating the API documentation you may want to
//! consider looking at the following pages:
//!
//! * [App](struct.App.html): This struct represents an actix-web
//!   application and is used to configure routes and other common
//!   settings.
//!
//! * [HttpServer](struct.HttpServer.html): This struct
//!   represents an HTTP server instance and is used to instantiate and
//!   configure servers.
//!
//! * [web](web/index.html): This module
//!   provides essential helper functions and types for application registration.
//!
//! * [HttpRequest](struct.HttpRequest.html) and
//!   [HttpResponse](struct.HttpResponse.html): These structs
//!   represent HTTP requests and responses and expose various methods
//!   for inspecting, creating and otherwise utilizing them.
//!
//! ## Features
//!
//! * Supported *HTTP/1.x* and *HTTP/2.0* protocols
//! * Streaming and pipelining
//! * Keep-alive and slow requests handling
//! * `WebSockets` server/client
//! * Transparent content compression/decompression (br, gzip, deflate)
//! * Configurable request routing
//! * Multipart streams
//! * SSL support with OpenSSL or `native-tls`
//! * Middlewares (`Logger`, `Session`, `CORS`, `DefaultHeaders`)
//! * Supports [Actix actor framework](https://github.com/actix/actix)
//! * Supported Rust version: 1.39 or later
//!
//! ## Package feature
//!
//! * `client` - enables http client (default enabled)
//! * `compress` - enables content encoding compression support (default enabled)
//! * `openssl` - enables ssl support via `openssl` crate, supports `http/2`
//! * `rustls` - enables ssl support via `rustls` crate, supports `http/2`
//! * `secure-cookies` - enables secure cookies support, includes `ring` crate as
//!   dependency
#![allow(clippy::type_complexity, clippy::new_without_default)]

mod app;
mod app_service;
mod config;
mod data;
pub mod error;
mod extract;
pub mod guard;
mod handler;
mod info;
pub mod middleware;
mod request;
mod resource;
mod responder;
mod rmap;
mod route;
mod scope;
mod server;
mod service;
pub mod test;
mod types;
pub mod web;

#[doc(hidden)]
pub use actix_web_codegen::*;

// re-export for convenience
pub use actix_http::Response as HttpResponse;
pub use actix_http::{body, cookie, http, Error, HttpMessage, ResponseError, Result};

pub use crate::app::App;
pub use crate::extract::FromRequest;
pub use crate::request::HttpRequest;
pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::scope::Scope;
pub use crate::server::HttpServer;

pub mod dev {
    //! The `actix-web` prelude for library developers
    //!
    //! The purpose of this module is to alleviate imports of many common actix
    //! traits by adding a glob import to the top of actix heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use actix_web::dev::*;
    //! ```

    pub use crate::config::{AppConfig, AppService};
    #[doc(hidden)]
    pub use crate::handler::Factory;
    pub use crate::info::ConnectionInfo;
    pub use crate::rmap::ResourceMap;
    pub use crate::service::{
        HttpServiceFactory, ServiceRequest, ServiceResponse, WebService,
    };

    pub use crate::types::form::UrlEncoded;
    pub use crate::types::json::JsonBody;
    pub use crate::types::readlines::Readlines;

    pub use actix_http::body::{Body, BodySize, MessageBody, ResponseBody, SizedStream};
    #[cfg(feature = "compress")]
    pub use actix_http::encoding::Decoder as Decompress;
    pub use actix_http::ResponseBuilder as HttpResponseBuilder;
    pub use actix_http::{
        Extensions, Payload, PayloadStream, RequestHead, ResponseHead,
    };
    pub use actix_router::{Path, ResourceDef, ResourcePath, Url};
    pub use actix_server::Server;
    pub use actix_service::{Service, Transform};

    pub(crate) fn insert_slash(mut patterns: Vec<String>) -> Vec<String> {
        for path in &mut patterns {
            if !path.is_empty() && !path.starts_with('/') {
                path.insert(0, '/');
            };
        }
        patterns
    }

    use crate::http::header::ContentEncoding;
    use actix_http::{Response, ResponseBuilder};

    struct Enc(ContentEncoding);

    /// Helper trait that allows to set specific encoding for response.
    pub trait BodyEncoding {
        /// Get content encoding
        fn get_encoding(&self) -> Option<ContentEncoding>;

        /// Set content encoding
        fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self;
    }

    impl BodyEncoding for ResponseBuilder {
        fn get_encoding(&self) -> Option<ContentEncoding> {
            if let Some(ref enc) = self.extensions().get::<Enc>() {
                Some(enc.0)
            } else {
                None
            }
        }

        fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
            self.extensions_mut().insert(Enc(encoding));
            self
        }
    }

    impl<B> BodyEncoding for Response<B> {
        fn get_encoding(&self) -> Option<ContentEncoding> {
            if let Some(ref enc) = self.extensions().get::<Enc>() {
                Some(enc.0)
            } else {
                None
            }
        }

        fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
            self.extensions_mut().insert(Enc(encoding));
            self
        }
    }
}

pub mod client {
    //! An HTTP Client
    //!
    //! ```rust
    //! use actix_web::client::Client;
    //!
    //! #[actix_rt::main]
    //! async fn main() {
    //!    let mut client = Client::default();
    //!
    //!    // Create request builder and send request
    //!    let response = client.get("http://www.rust-lang.org")
    //!       .header("User-Agent", "Actix-web")
    //!       .send().await;                      // <- Send http request
    //!
    //!    println!("Response: {:?}", response);
    //! }
    //! ```
    pub use awc::error::{
        ConnectError, InvalidUrl, PayloadError, SendRequestError, WsClientError,
    };
    pub use awc::{
        test, Client, ClientBuilder, ClientRequest, ClientResponse, Connector,
    };
}
<|endoftext|>


<commit_before>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

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

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    /// The sprites of the game.
    pub sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: &P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: &P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sprite.
#[derive(Clone)]
pub struct Sprite {
    /// The index of the resource name in the string table.
    pub name_index: usize,
    /// The width of the sprite
    pub width: u32,
    /// The height of the sprite
    pub height: u32,
    pub unknown: Vec<u8>,
}

/// A collection of sprites.
pub struct Sprites {
    /// The sprites
    pub sprites: Vec<Sprite>,
}

/// A collection of backgrounds.
struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
struct Scripts {
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
struct Variables {
    pub variables: Vec<Variable>,
}

/// A game maker function.
struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
struct Functions {
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    offset: u32, // Offset of data in the texture data
}

/// A collection of textures.
struct Textures {
    pub textures: Vec<Texture>,
    texture_data: Vec<u8>,
}

struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
    size: u32, // Fuck it
}
<commit_msg>Revert "Make "unknown" of Sprite public"<commit_after>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

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

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    /// The sprites of the game.
    pub sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: &P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: &P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sprite.
#[derive(Clone)]
pub struct Sprite {
    /// The index of the resource name in the string table.
    pub name_index: usize,
    /// The width of the sprite
    pub width: u32,
    /// The height of the sprite
    pub height: u32,
    unknown: Vec<u8>,
}

/// A collection of sprites.
pub struct Sprites {
    /// The sprites
    pub sprites: Vec<Sprite>,
}

/// A collection of backgrounds.
struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
struct Scripts {
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
struct Variables {
    pub variables: Vec<Variable>,
}

/// A game maker function.
struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
struct Functions {
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    offset: u32, // Offset of data in the texture data
}

/// A collection of textures.
struct Textures {
    pub textures: Vec<Texture>,
    texture_data: Vec<u8>,
}

struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
    size: u32, // Fuck it
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

//! Strided slices.
//!
//! This library provides two types `Strided` and `MutStrided` as
//! generalised forms of `&[T]` and `&mut [T]` respectively, where the
//! elements are regularly spaced in memory, but not necessarily
//! immediately adjacently.
//!
//! For example, given an underlying array `[1, 2, 3, 4, 5]`, the
//! elements `[1, 3, 5]` are a strided slice with stride 2, and
//! `[1, 4]` has stride 3. Any slice can be regarded as a strided slice
//! with stride 1.
//!
//! This provides functionality through which one can safely and
//! efficiently manipulate every `n`th element of a slice (even a
//! mutable one) as close as possible to it being a conventional
//! slice. This releases one from worries about stride bookkeeping,
//! aliasing of `&mut` or any `unsafe` code.
//!
//! # Quick start
//!
//! The work-horse function is `.substrides(n)`, which returns an
//! iterator across a series of `n` new strided slices, each of which
//! points to every `n`th element, and each of which starts at the
//! next successive offset. For example, the following has `n = 3`.
//!
//! ```rust
//! use strided::MutStrided;
//!
//! let mut v = [1u8, 2, 3, 4, 5];
//! let mut all = MutStrided::new(&mut v);
//!
//! let mut substrides = all.substrides(3);
//!
//! let a = substrides.next().unwrap();
//! let b = substrides.next().unwrap();
//! let c = substrides.next().unwrap();
//! assert!(substrides.next().is_none()); // there was exactly 3.
//!
//! assert_eq!(a, MutStrided::new(&mut [1, 4]));
//! assert_eq!(b, MutStrided::new(&mut [2, 5]));
//! assert_eq!(c, MutStrided::new(&mut [3]));
//! ```
//!
//! The common case of `n = 2` has an abbreviation `substrides2`,
//! which takes the liberty of returns a tuple rather than an iterator
//! to make direct destructuring work. Continuing with the values
//! above, `left` and `right` point to alternate elements, starting at
//! index `0` and `1` of their parent slice respectively.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (left, right) = all.reborrow().substrides2();
//!
//! assert_eq!(left, MutStrided::new(&mut [1, 3, 5]));
//! assert_eq!(right, MutStrided::new(&mut [2, 4]));
//! ```
//!
//! A lot of the conventional slice functionality is available, such
//! as indexing (both sugary and non-panicking), iterators and
//! slicing.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.reborrow().substrides2();
//! assert_eq!(left[2], 5);
//! assert!(right.get(10).is_none()); // out of bounds
//!
//! left[2] += 10;
//! match left.get_mut(0) {
//!     Some(val) => *val -= 3,
//!     None => {}
//! }
//!
//! assert_eq!(right.iter().fold(0, |sum, a| sum + *a), 2 + 4);
//! for val in left.iter_mut() {
//!     *val /= 2
//! }
//! ```
//!
//! Many of the methods of `MutStrided` take `self` by-value and so
//! consume ownership, this makes the `reborrow` method one of the
//! most important. It converts a `&'b mut MutStrided<'a, T>` to a
//! `MutStrided<'b, T>`, that is, allows temporarily viewing a strided
//! slices as one with a shorter lifetime. The temporary can then be
//! used with the consuming methods, and the parent slice can still be
//! used after that borrow has finished. For example, all of the
//! splitting and slicing methods on `MutStrided` consume ownership,
//! and so `reborrow` is necessary there to continue using, in this
//! case, `left`.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.reborrow().substrides2();
//! assert_eq!(left.reborrow().slice(1, 3), MutStrided::new(&mut [3, 5]));
//! assert_eq!(left.reborrow().slice_from(2), MutStrided::new(&mut [5]));
//! assert_eq!(left.reborrow().slice_to(2), MutStrided::new(&mut [1, 3]));
//!
//! assert_eq!(right.split_at(1),
//!            (MutStrided::new(&mut [2]), MutStrided::new(&mut [4])));
//! ```
//!
//! These contortions are necessary to ensure that `&mut`s cannot
//! alias, while still maintaining flexibility: leaving elements with
//! the maximum possible lifetime (i.e. that of the non-strided slices
//! which they lie in). Theoretically they are necessary with
//! `&mut []` too, but the compiler inserts implicit reborrows and so
//! one rarely needs to do them manually.
//!
//! The shared `Strided` is equivalent to `&[]` and only handles `&`
//! references, making ownership transfer and `reborrow` unnecessary,
//! so all its methods act identically to those on `&[]`.

#[cfg(test)] extern crate test;

pub use base::{Items, MutItems};

pub use mut_::Strided as MutStrided;
pub use mut_::Substrides as MutSubstrides;

pub use imm::Strided as Strided;
pub use imm::Substrides as Substrides;

macro_rules! eq {
    ($stride: expr, $expected: expr) => {
        eq!($stride, $expected, iter)
    };

    ($stride: expr, $expected: expr, $method: ident) => {{
        let e: &[_] = $expected;
        let mut _stride = $stride;
        assert_eq!(_stride.len(), e.len());
        let mut iter = _stride.$method();
        assert_eq!(iter.size_hint(),(e.len(), Some(e.len())));
        let vals = iter.by_ref().map(|s| *s).collect::<Vec<_>>();
        if vals.as_slice() != e {
            panic!("mismatched: {}, {}", vals, e);
        }
        assert_eq!(iter.size_hint(),(0, Some(0)));
    }}
}

mod base;
mod mut_;
mod imm;

#[cfg(test)]
mod bench {
    use super::Strided;
    use test::Bencher as B;
    use test;

    const N: uint = 100;

    #[bench]
    fn iter_slice(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        b.iter(|| {
            test::black_box(&v);
            for e in v.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_1(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        let s = Strided::new(&*v);
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_13(b: &mut B) {
        let v = Vec::from_fn(N * 13, |i| i);
        let s = Strided::new(&*v);
        let s = s.substrides(13).next().unwrap();
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }
}
<commit_msg>Add the FFT example.<commit_after>#![feature(macro_rules)]

//! Strided slices.
//!
//! This library provides two types `Strided` and `MutStrided` as
//! generalised forms of `&[T]` and `&mut [T]` respectively, where the
//! elements are regularly spaced in memory, but not necessarily
//! immediately adjacently.
//!
//! For example, given an underlying array `[1, 2, 3, 4, 5]`, the
//! elements `[1, 3, 5]` are a strided slice with stride 2, and
//! `[1, 4]` has stride 3. Any slice can be regarded as a strided slice
//! with stride 1.
//!
//! This provides functionality through which one can safely and
//! efficiently manipulate every `n`th element of a slice (even a
//! mutable one) as close as possible to it being a conventional
//! slice. This releases one from worries about stride bookkeeping,
//! aliasing of `&mut` or any `unsafe` code.
//!
//! # Quick start
//!
//! The work-horse function is `.substrides(n)`, which returns an
//! iterator across a series of `n` new strided slices, each of which
//! points to every `n`th element, and each of which starts at the
//! next successive offset. For example, the following has `n = 3`.
//!
//! ```rust
//! use strided::MutStrided;
//!
//! let mut v = [1u8, 2, 3, 4, 5];
//! let mut all = MutStrided::new(&mut v);
//!
//! let mut substrides = all.substrides(3);
//!
//! let a = substrides.next().unwrap();
//! let b = substrides.next().unwrap();
//! let c = substrides.next().unwrap();
//! assert!(substrides.next().is_none()); // there was exactly 3.
//!
//! assert_eq!(a, MutStrided::new(&mut [1, 4]));
//! assert_eq!(b, MutStrided::new(&mut [2, 5]));
//! assert_eq!(c, MutStrided::new(&mut [3]));
//! ```
//!
//! The common case of `n = 2` has an abbreviation `substrides2`,
//! which takes the liberty of returns a tuple rather than an iterator
//! to make direct destructuring work. Continuing with the values
//! above, `left` and `right` point to alternate elements, starting at
//! index `0` and `1` of their parent slice respectively.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (left, right) = all.reborrow().substrides2();
//!
//! assert_eq!(left, MutStrided::new(&mut [1, 3, 5]));
//! assert_eq!(right, MutStrided::new(&mut [2, 4]));
//! ```
//!
//! A lot of the conventional slice functionality is available, such
//! as indexing (both sugary and non-panicking), iterators and
//! slicing.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.reborrow().substrides2();
//! assert_eq!(left[2], 5);
//! assert!(right.get(10).is_none()); // out of bounds
//!
//! left[2] += 10;
//! match left.get_mut(0) {
//!     Some(val) => *val -= 3,
//!     None => {}
//! }
//!
//! assert_eq!(right.iter().fold(0, |sum, a| sum + *a), 2 + 4);
//! for val in left.iter_mut() {
//!     *val /= 2
//! }
//! ```
//!
//! Many of the methods of `MutStrided` take `self` by-value and so
//! consume ownership, this makes the `reborrow` method one of the
//! most important. It converts a `&'b mut MutStrided<'a, T>` to a
//! `MutStrided<'b, T>`, that is, allows temporarily viewing a strided
//! slices as one with a shorter lifetime. The temporary can then be
//! used with the consuming methods, and the parent slice can still be
//! used after that borrow has finished. For example, all of the
//! splitting and slicing methods on `MutStrided` consume ownership,
//! and so `reborrow` is necessary there to continue using, in this
//! case, `left`.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.reborrow().substrides2();
//! assert_eq!(left.reborrow().slice(1, 3), MutStrided::new(&mut [3, 5]));
//! assert_eq!(left.reborrow().slice_from(2), MutStrided::new(&mut [5]));
//! assert_eq!(left.reborrow().slice_to(2), MutStrided::new(&mut [1, 3]));
//!
//! assert_eq!(right.split_at(1),
//!            (MutStrided::new(&mut [2]), MutStrided::new(&mut [4])));
//! ```
//!
//! These contortions are necessary to ensure that `&mut`s cannot
//! alias, while still maintaining flexibility: leaving elements with
//! the maximum possible lifetime (i.e. that of the non-strided slices
//! which they lie in). Theoretically they are necessary with
//! `&mut []` too, but the compiler inserts implicit reborrows and so
//! one rarely needs to do them manually.
//!
//! The shared `Strided` is equivalent to `&[]` and only handles `&`
//! references, making ownership transfer and `reborrow` unnecessary,
//! so all its methods act identically to those on `&[]`.
//!
//! # Example
//!
//! The [fast Fourier transform
//! (FFT)](https://en.wikipedia.org/wiki/Fast_Fourier_transform) is a
//! signal processing algorithm that performs a discrete Fourier
//! transform (DFT) of length `n` in `O(n log n)` time. A DFT breaks a
//! waveform into the sum of sines and cosines, and is an important
//! part of many other algorithms due to certain nice properties of
//! the Fourier transform.
//!
//! The first FFT algorithm was the [Cooley-Tukey
//! algorithm](https://en.wikipedia.org/wiki/Cooley-Tukey_FFT_algorithm). The
//! decimation-in-time variant works by computing the FFT of
//! equal-length subarrays of equally spaced elements and then
//! combining these together into the desired result. This sort of
//! spacing is exactly the striding provided by this library, and
//! hence this library can be used to create an FFT algorithm in a
//! very natural way.
//!
//! Below is an implementation of the radix-2 case, that is, when the
//! length `n` is a power of two, in this case, only two strided
//! subarrays are necessary: exactly the alternating ones provided by
//! `substrides2`. Note the use of `reborrow` to allow `start` and
//! `end` to be used for the recursive `fft` calls and then again
//! later in the loop.
//!
//! ```rust
//! extern crate strided;
//! extern crate num; // https://github.com/rust-lang/num
//! use std::num::{Int, Float};
//! use num::complex::{Complex, Complex64};
//! use strided::{MutStrided, Strided};
//!
//! /// Writes the forward DFT of `input` to `output`.
//! fn fft(input: Strided<Complex64>, mut output: MutStrided<Complex64>) {
//!     // check it's a power of two.
//!     assert!(input.len() == output.len() && input.len().count_ones() == 1);
//!
//!     // base case: the DFT of a single element is itself.
//!     if input.len() == 1 {
//!         output[0] = input[0];
//!         return
//!     }
//!
//!     // split the input into two arrays of alternating elements ("decimate in time")
//!     let (evens, odds) = input.substrides2();
//!     // break the output into two halves (front and back, not alternating)
//!     let (mut start, mut end) = output.split_at(input.len() / 2);
//!
//!     // recursively perform two FFTs on alternating elements of the input, writing the
//!     // results into the first and second half of the output array respectively.
//!     fft(evens, start.reborrow());
//!     fft(odds, end.reborrow());
//!
//!     let two_pi: f64 = Float::two_pi();
//!     // exp(-2πi/N)
//!     let twiddle = Complex::from_polar(&1.0, &(-two_pi / input.len() as f64));
//!
//!     let mut factor = Complex::one();
//!
//!     // combine the subFFTs with the relations:
//!     //   X_k = E_k + exp(-2πki/N) * O_k
//!     //   X_{k+N/2} = E_k - exp(-2πki/N) * O_k
//!     for (even, odd) in start.iter_mut().zip(end.iter_mut()) {
//!         let twiddled = factor * *odd;
//!         let e = *even;
//!
//!         *even = e + twiddled;
//!         *odd = e - twiddled;
//!         factor = factor * twiddle;
//!     }
//! }
//!
//! fn main() {
//!     let a = [Complex::new(2., 0.), Complex::new(1., 0.),
//!              Complex::new(2., 0.), Complex::new(1., 0.)];
//!     let mut b = [Complex::new(0., 0.), .. 4];
//!
//!     fft(Strided::new(&a), MutStrided::new(&mut b));
//!     println!("forward: {} -> {}", a.as_slice(), b.as_slice());
//! }
//! ```
//!
//! The above definitely has complexity `O(n log n)`, but it has a
//! much larger constant factor than an optimised library like
//! [FFTW](http://www.fftw.org/).

#[cfg(test)] extern crate test;

pub use base::{Items, MutItems};

pub use mut_::Strided as MutStrided;
pub use mut_::Substrides as MutSubstrides;

pub use imm::Strided as Strided;
pub use imm::Substrides as Substrides;

macro_rules! eq {
    ($stride: expr, $expected: expr) => {
        eq!($stride, $expected, iter)
    };

    ($stride: expr, $expected: expr, $method: ident) => {{
        let e: &[_] = $expected;
        let mut _stride = $stride;
        assert_eq!(_stride.len(), e.len());
        let mut iter = _stride.$method();
        assert_eq!(iter.size_hint(),(e.len(), Some(e.len())));
        let vals = iter.by_ref().map(|s| *s).collect::<Vec<_>>();
        if vals.as_slice() != e {
            panic!("mismatched: {}, {}", vals, e);
        }
        assert_eq!(iter.size_hint(),(0, Some(0)));
    }}
}

mod base;
mod mut_;
mod imm;

#[cfg(test)]
mod bench {
    use super::Strided;
    use test::Bencher as B;
    use test;

    const N: uint = 100;

    #[bench]
    fn iter_slice(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        b.iter(|| {
            test::black_box(&v);
            for e in v.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_1(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        let s = Strided::new(&*v);
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_13(b: &mut B) {
        let v = Vec::from_fn(N * 13, |i| i);
        let s = Strided::new(&*v);
        let s = s.substrides(13).next().unwrap();
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }
}
<|endoftext|>