<commit_before>//! Utility functions to write nifti images.

use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};

use byteordered::{ByteOrdered, Endian};
use flate2::write::GzEncoder;
use flate2::Compression;
use ndarray::{ArrayBase, Axis, Data, Dimension, RemoveAxis};
use safe_transmute::{transmute_to_bytes, TriviallyTransmutable};

use crate::{
    header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
    util::{adapt_bytes, is_gz_file, is_hdr_file},
    volume::shape::Dim,
    DataElement, NiftiHeader, NiftiType, Result,
};

/// Write a nifti file (.nii or .nii.gz).
///
/// If a `reference` is given, it will be used to fill most of the header's fields. Otherwise, a
/// default `NiftiHeader` will be built and written. In all cases, the `dim`, `datatype` and
/// `bitpix` fields will depend only on `data`, not on the header. This means that the `datatype`
/// defined in `reference` will be ignored. Because of this, `scl_slope` will be set to 1.0 and
/// `scl_inter` to 0.0.
pub fn write_nifti<P, A, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = A>,
    A: DataElement,
    A: TriviallyTransmutable,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, A::DATA_TYPE)?;

    // Need the transpose for fortran ordering used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_data::<_, A, _, _, _, _>(writer, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;
            let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_data::<_, A, _, _, _, _>(data_writer, data)?;
        }
    }

    Ok(())
}

/// Write a RGB nifti file (.nii or .nii.gz).
///
/// If a `reference` is given, it will be used to fill most of the header's fields, except those
/// necessary to be recognized as a RGB image. `scl_slope` will be set to 1.0 and `scl_inter` to
/// 0.0. If `reference` is not given, a default `NiftiHeader` will be built and written.
pub fn write_rgb_nifti<P, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = [u8; 3]>,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, NiftiType::Rgb24)?;

    // Need the transpose for fortran used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_data::<_, u8, _, _, _, _>(writer, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;

            let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_data::<_, u8, _, _, _, _>(data_writer, data)?;
        }
    }

    Ok(())
}

fn prepare_header_and_paths<P, T, D>(
    header_path: P,
    data: &ArrayBase<T, D>,
    reference: Option<&NiftiHeader>,
    datatype: NiftiType,
) -> Result<(NiftiHeader, PathBuf)>
where
    P: AsRef<Path>,
    T: Data,
    D: Dimension,
{
    // If no reference header is given, use the default.
    let reference = match reference {
        Some(r) => r.clone(),
        None => {
            let mut header = NiftiHeader::default();
            header.sform_code = 2;
            header
        }
    };

    let mut header = NiftiHeader {
        dim: *Dim::from_slice(data.shape())?.raw(),
        sizeof_hdr: 348,
        datatype: datatype as i16,
        bitpix: (datatype.size_of() * 8) as i16,
        vox_offset: 352.0,
        scl_inter: 0.0,
        scl_slope: 1.0,
        magic: *MAGIC_CODE_NIP1,
        // All other fields are copied from reference header
        ..reference
    };

    // The only acceptable length is 80. If different, try to set it.
    header.validate_description()?;

    let mut path_buf = PathBuf::from(header_path.as_ref());
    let data_path = if is_hdr_file(&header_path) {
        header.vox_offset = 0.0;
        header.magic = *MAGIC_CODE_NI1;
        let data_path = if is_gz_file(&header_path) {
            let _ = path_buf.set_extension("");
            path_buf.with_extension("img.gz")
        } else {
            path_buf.with_extension("img")
        };
        data_path
    } else {
        path_buf
    };

    Ok((header, data_path))
}

fn write_header<W, E>(mut writer: ByteOrdered<W, E>, header: &NiftiHeader) -> Result<()>
where
    W: Write,
    E: Endian,
{
    writer.write_i32(header.sizeof_hdr)?;
    writer.write_all(&header.data_type)?;
    writer.write_all(&header.db_name)?;
    writer.write_i32(header.extents)?;
    writer.write_i16(header.session_error)?;
    writer.write_u8(header.regular)?;
    writer.write_u8(header.dim_info)?;
    for s in &header.dim {
        writer.write_u16(*s)?;
    }
    writer.write_f32(header.intent_p1)?;
    writer.write_f32(header.intent_p2)?;
    writer.write_f32(header.intent_p3)?;
    writer.write_i16(header.intent_code)?;
    writer.write_i16(header.datatype)?;
    writer.write_i16(header.bitpix)?;
    writer.write_i16(header.slice_start)?;
    for f in &header.pixdim {
        writer.write_f32(*f)?;
    }
    writer.write_f32(header.vox_offset)?;
    writer.write_f32(header.scl_slope)?;
    writer.write_f32(header.scl_inter)?;
    writer.write_i16(header.slice_end)?;
    writer.write_u8(header.slice_code)?;
    writer.write_u8(header.xyzt_units)?;
    writer.write_f32(header.cal_max)?;
    writer.write_f32(header.cal_min)?;
    writer.write_f32(header.slice_duration)?;
    writer.write_f32(header.toffset)?;
    writer.write_i32(header.glmax)?;
    writer.write_i32(header.glmin)?;

    writer.write_all(&header.descrip)?;
    writer.write_all(&header.aux_file)?;
    writer.write_i16(header.qform_code)?;
    writer.write_i16(header.sform_code)?;
    for f in &[
        header.quatern_b,
        header.quatern_c,
        header.quatern_d,
        header.quatern_x,
        header.quatern_y,
        header.quatern_z,
    ] {
        writer.write_f32(*f)?;
    }
    for f in header
        .srow_x
        .iter()
        .chain(&header.srow_y)
        .chain(&header.srow_z)
    {
        writer.write_f32(*f)?;
    }
    writer.write_all(&header.intent_name)?;
    writer.write_all(&header.magic)?;

    // Empty 4 bytes after the header
    // TODO Support writing extension data.
    writer.write_u32(0)?;

    Ok(())
}

/// Write the data in 'f' order.
///
/// Like NiBabel, we iterate by "slice" to improve speed and use less memory.
fn write_data<A, B, S, D, W, E>(mut writer: ByteOrdered<W, E>, data: ArrayBase<S, D>) -> Result<()>
where
    S: Data<Elem = A>,
    A: TriviallyTransmutable,
    D: Dimension + RemoveAxis,
    W: Write,
    E: Endian + Copy,
{
    let mut iter = data.axis_iter(Axis(0));
    if let Some(arr_data) = iter.next() {
        // Keep slice voxels in a separate array to ensure `C` ordering even after `into_shape`.
        let mut slice = arr_data.to_owned();
        write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        for arr_data in iter {
            slice.assign(&arr_data);
            write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        }
    }
    Ok(())
}

fn write_slice<A, B, S, D, W, E>(
    writer: ByteOrdered<&mut W, E>,
    data: ArrayBase<S, D>,
) -> Result<()>
where
    S: Data<Elem = A>,
    A: Clone + TriviallyTransmutable,
    D: Dimension,
    W: Write,
    E: Endian,
{
    let len = data.len();
    let arr_data = data.into_shape(len).unwrap();
    let slice = arr_data.as_slice().unwrap();
    let bytes = transmute_to_bytes(slice);
    let (writer, endianness) = writer.into_parts();
    let bytes = adapt_bytes::<B, _>(&bytes, endianness);
    writer.write_all(&*bytes)?;
    Ok(())
}
<commit_msg>Fix writing (..., 1) images<commit_after>//! Utility functions to write nifti images.

use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};

use byteordered::{ByteOrdered, Endian};
use flate2::write::GzEncoder;
use flate2::Compression;
use ndarray::{ArrayBase, Axis, Data, Dimension, RemoveAxis};
use safe_transmute::{transmute_to_bytes, TriviallyTransmutable};

use crate::{
    header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
    util::{adapt_bytes, is_gz_file, is_hdr_file},
    volume::shape::Dim,
    DataElement, NiftiHeader, NiftiType, Result,
};

/// Write a nifti file (.nii or .nii.gz).
///
/// If a `reference` is given, it will be used to fill most of the header's fields. Otherwise, a
/// default `NiftiHeader` will be built and written. In all cases, the `dim`, `datatype` and
/// `bitpix` fields will depend only on `data`, not on the header. This means that the `datatype`
/// defined in `reference` will be ignored. Because of this, `scl_slope` will be set to 1.0 and
/// `scl_inter` to 0.0.
pub fn write_nifti<P, A, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = A>,
    A: DataElement,
    A: TriviallyTransmutable,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, A::DATA_TYPE)?;

    // Need the transpose for fortran ordering used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_data::<_, A, _, _, _, _>(writer, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;
            let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_data::<_, A, _, _, _, _>(data_writer, data)?;
        }
    }

    Ok(())
}

/// Write a RGB nifti file (.nii or .nii.gz).
///
/// If a `reference` is given, it will be used to fill most of the header's fields, except those
/// necessary to be recognized as a RGB image. `scl_slope` will be set to 1.0 and `scl_inter` to
/// 0.0. If `reference` is not given, a default `NiftiHeader` will be built and written.
pub fn write_rgb_nifti<P, S, D>(
    header_path: P,
    data: &ArrayBase<S, D>,
    reference: Option<&NiftiHeader>,
) -> Result<()>
where
    P: AsRef<Path>,
    S: Data<Elem = [u8; 3]>,
    D: Dimension + RemoveAxis,
{
    let compression_level = Compression::fast();
    let is_gz = is_gz_file(&header_path);
    let (header, data_path) =
        prepare_header_and_paths(&header_path, data, reference, NiftiType::Rgb24)?;

    // Need the transpose for fortran used in nifti file format.
    let data = data.t();

    let header_file = File::create(header_path)?;
    if header.vox_offset > 0.0 {
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(writer.as_mut(), &header)?;
            write_data::<_, u8, _, _, _, _>(writer, data)?;
        }
    } else {
        let data_file = File::create(&data_path)?;
        if is_gz {
            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(header_file, compression_level),
                header.endianness,
            );
            write_header(writer.as_mut(), &header)?;
            let _ = writer.into_inner().finish()?;

            let mut writer = ByteOrdered::runtime(
                GzEncoder::new(data_file, compression_level),
                header.endianness,
            );
            write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?;
            let _ = writer.into_inner().finish()?;
        } else {
            let header_writer =
                ByteOrdered::runtime(BufWriter::new(header_file), header.endianness);
            write_header(header_writer, &header)?;

            let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness);
            write_data::<_, u8, _, _, _, _>(data_writer, data)?;
        }
    }

    Ok(())
}

fn prepare_header_and_paths<P, T, D>(
    header_path: P,
    data: &ArrayBase<T, D>,
    reference: Option<&NiftiHeader>,
    datatype: NiftiType,
) -> Result<(NiftiHeader, PathBuf)>
where
    P: AsRef<Path>,
    T: Data,
    D: Dimension,
{
    // If no reference header is given, use the default.
    let reference = match reference {
        Some(r) => r.clone(),
        None => {
            let mut header = NiftiHeader::default();
            header.sform_code = 2;
            header
        }
    };

    let mut header = NiftiHeader {
        dim: *Dim::from_slice(data.shape())?.raw(),
        sizeof_hdr: 348,
        datatype: datatype as i16,
        bitpix: (datatype.size_of() * 8) as i16,
        vox_offset: 352.0,
        scl_inter: 0.0,
        scl_slope: 1.0,
        magic: *MAGIC_CODE_NIP1,
        // All other fields are copied from reference header
        ..reference
    };

    // The only acceptable length is 80. If different, try to set it.
    header.validate_description()?;

    let mut path_buf = PathBuf::from(header_path.as_ref());
    let data_path = if is_hdr_file(&header_path) {
        header.vox_offset = 0.0;
        header.magic = *MAGIC_CODE_NI1;
        let data_path = if is_gz_file(&header_path) {
            let _ = path_buf.set_extension("");
            path_buf.with_extension("img.gz")
        } else {
            path_buf.with_extension("img")
        };
        data_path
    } else {
        path_buf
    };

    Ok((header, data_path))
}

fn write_header<W, E>(mut writer: ByteOrdered<W, E>, header: &NiftiHeader) -> Result<()>
where
    W: Write,
    E: Endian,
{
    writer.write_i32(header.sizeof_hdr)?;
    writer.write_all(&header.data_type)?;
    writer.write_all(&header.db_name)?;
    writer.write_i32(header.extents)?;
    writer.write_i16(header.session_error)?;
    writer.write_u8(header.regular)?;
    writer.write_u8(header.dim_info)?;
    for s in &header.dim {
        writer.write_u16(*s)?;
    }
    writer.write_f32(header.intent_p1)?;
    writer.write_f32(header.intent_p2)?;
    writer.write_f32(header.intent_p3)?;
    writer.write_i16(header.intent_code)?;
    writer.write_i16(header.datatype)?;
    writer.write_i16(header.bitpix)?;
    writer.write_i16(header.slice_start)?;
    for f in &header.pixdim {
        writer.write_f32(*f)?;
    }
    writer.write_f32(header.vox_offset)?;
    writer.write_f32(header.scl_slope)?;
    writer.write_f32(header.scl_inter)?;
    writer.write_i16(header.slice_end)?;
    writer.write_u8(header.slice_code)?;
    writer.write_u8(header.xyzt_units)?;
    writer.write_f32(header.cal_max)?;
    writer.write_f32(header.cal_min)?;
    writer.write_f32(header.slice_duration)?;
    writer.write_f32(header.toffset)?;
    writer.write_i32(header.glmax)?;
    writer.write_i32(header.glmin)?;

    writer.write_all(&header.descrip)?;
    writer.write_all(&header.aux_file)?;
    writer.write_i16(header.qform_code)?;
    writer.write_i16(header.sform_code)?;
    for f in &[
        header.quatern_b,
        header.quatern_c,
        header.quatern_d,
        header.quatern_x,
        header.quatern_y,
        header.quatern_z,
    ] {
        writer.write_f32(*f)?;
    }
    for f in header
        .srow_x
        .iter()
        .chain(&header.srow_y)
        .chain(&header.srow_z)
    {
        writer.write_f32(*f)?;
    }
    writer.write_all(&header.intent_name)?;
    writer.write_all(&header.magic)?;

    // Empty 4 bytes after the header
    // TODO Support writing extension data.
    writer.write_u32(0)?;

    Ok(())
}

/// Write the data in 'f' order.
///
/// Like NiBabel, we iterate by "slice" to improve speed and use less memory.
fn write_data<A, B, S, D, W, E>(mut writer: ByteOrdered<W, E>, data: ArrayBase<S, D>) -> Result<()>
where
    S: Data<Elem = A>,
    A: TriviallyTransmutable,
    D: Dimension + RemoveAxis,
    W: Write,
    E: Endian + Copy,
{
    // We always write the image by iterating on the first axis, thus
    //   3D (depth, height, width) => per axial slice
    //   4D (time, depth, height, width) => per volume
    // However, there's a problem when dim == (1, ...). We must iterate by the first non-one length
    // axis, otherwise the image will be written in the wrong ordering. See issue #63.
    let first_good_axis = data.shape().iter().position(|&d| d > 1).unwrap_or(0);
    let mut iter = data.axis_iter(Axis(first_good_axis));
    if let Some(arr_data) = iter.next() {
        // Keep slice voxels in a separate array to ensure `C` ordering even after `into_shape`.
        let mut slice = arr_data.to_owned();
        write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        for arr_data in iter {
            slice.assign(&arr_data);
            write_slice::<_, B, _, _, _, _>(writer.as_mut(), slice.view())?;
        }
    }
    Ok(())
}

fn write_slice<A, B, S, D, W, E>(
    writer: ByteOrdered<&mut W, E>,
    data: ArrayBase<S, D>,
) -> Result<()>
where
    S: Data<Elem = A>,
    A: Clone + TriviallyTransmutable,
    D: Dimension,
    W: Write,
    E: Endian,
{
    let len = data.len();
    let arr_data = data.into_shape(len).unwrap();
    let slice = arr_data.as_slice().unwrap();
    let bytes = transmute_to_bytes(slice);
    let (writer, endianness) = writer.into_parts();
    let bytes = adapt_bytes::<B, _>(&bytes, endianness);
    writer.write_all(&*bytes)?;
    Ok(())
}
<|endoftext|>


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

// xfail-fast - ICE
trait Foo {
    fn foo();
}

trait Bar : Foo {
    fn bar();
}

fn main() {}

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

trait Foo {
    fn foo();
}

trait Bar : Foo {
    fn bar();
}

fn main() {}

<|endoftext|>


<commit_before>
extern crate clap;

// Time Start: Mon, 16 Dec 2019 07:42:46 -0500
// Time Finish 1: Mon, 16 Dec 2019 08:30:39 -0500 (47 minutes, 53 seconds)
// Time Finish 2:
// Time Total:

use std::fs;

use clap::{Arg, App};

const PAT1: [i32; 4] = [0,1,0,-1];

fn fft(vec: &Vec<i32>, pat: &[i32], n: u32) -> Vec<i32> {
    let mut new = vec.clone();
    let mut vec = Vec::with_capacity(vec.len());
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        // let (mut vec, mut new) = (new, vec);
        new.clear();
        for place in 0..vec.len() {
            let mut val = 0;
            let mut pat_idx = 0;
            let mut repeat = place;
            for idx in 0..vec.len() {
                if repeat == 0 {
                    pat_idx = (pat_idx + 1) % pat.len();
                    repeat = place + 1;
                }
                val += vec[idx] * pat[pat_idx];
                val = val.signum() * (val.abs() % 100000000);
                repeat -= 1;
            }
            new.push(val.abs() % 10);
        }
    }
    return new;
}

fn repeat<T: Clone>(vec: &Vec<T>, n: usize) -> Vec<T> {
    let mut rv = Vec::with_capacity(n * vec.len());
    for _ in 0..n {
        rv.extend_from_slice(&vec[0..vec.len()]);
    }
    return rv;
}

fn num_at(vec: &Vec<i32>, idx: usize, len: usize) -> i32 {
    let mut rv = 0;
    for i in 0..len {
        rv = 10*rv + vec[idx + i];
    }
    return rv;
}

fn load(fname: &str) -> Vec<i32> {
    let contents = fs::read_to_string(fname)
        .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));
    return contents.trim().chars().map(|c| c.to_digit(10).unwrap_or_else(|| panic!("Parse error")) as i32).collect();
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 16")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("16.in");
    let vec = load(&fname);
    println!("Part 1: {}", num_at(&fft(&vec, &PAT1, 100), 0, 8));

    let vec2 = repeat(&vec, 10000);
    let part2 = fft(&vec2, &PAT1, 100);
    println!("Part 2: {}", num_at(&part2, num_at(&part2, 0, 7) as usize, 8));
}

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

    #[test]
    fn example1() {
        assert_eq!(fft(&vec![1,2,3,4,5,6,7,8], &PAT1, 1), vec![4,8,2,2,6,1,5,8]);
        assert_eq!(fft(&vec![4,8,2,2,6,1,5,8], &PAT1, 1), vec![3,4,0,4,0,4,3,8]);
        assert_eq!(fft(&vec![3,4,0,4,0,4,3,8], &PAT1, 1), vec![0,3,4,1,5,5,1,8]);
        assert_eq!(fft(&vec![0,3,4,1,5,5,1,8], &PAT1, 1), vec![0,1,0,2,9,4,9,8]);
        assert_eq!(fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0,8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100)[0..8], [2,4,1,7,6,1,7,6]);
        assert_eq!(fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9,1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100)[0..8], [7,3,7,4,5,4,1,8]);
        assert_eq!(fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9,9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100)[0..8], [5,2,4,3,2,1,3,3]);
    }
}
<commit_msg>Day 16<commit_after>
extern crate clap;

// Time Start: Mon, 16 Dec 2019 07:42:46 -0500
// Time Finish 1: Mon, 16 Dec 2019 08:30:39 -0500 (47 minutes, 53 seconds)
// Time Finish 2:
// Time Total:

use std::fs;

use clap::{Arg, App};

const PAT1: [i32; 4] = [0,1,0,-1];

fn fft(vec: &Vec<i32>, pat: &[i32], n: u32, offset: usize) -> Vec<i32> {
    let len = vec.len();
    let mut new = vec.clone();
    let mut vec = Vec::with_capacity(len);
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        new.clear();
        for place in 0..len {
            let mut val = 0;
            let mut pat_idx = 0;
            let mut repeat = place;
            for idx in 0..len {
                if repeat == 0 {
                    pat_idx = (pat_idx + 1) % pat.len();
                    repeat = place + offset + 1;
                }
                val += vec[idx] * pat[pat_idx];
                val = val.signum() * (val.abs() % 1_000_000);
                repeat -= 1;
            }
            new.push(val.abs() % 10);
        }
    }
    return new;
}

fn fft_tail(vec: &Vec<i32>, n: u32, tail_len: usize) -> i32 {
    let len = vec.len();
    let mut new = vec.clone();
    new.reverse();
    let mut vec = Vec::with_capacity(len);
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        new.clear();
        let mut val = 0;
        for i in 0..len {
            val += vec[i];
            new.push(val % 10);
        }
    }
    new.reverse();
    return num_at(&new, 0, tail_len);
}

fn repeat<T: Clone>(vec: &Vec<T>, n: usize) -> Vec<T> {
    let mut rv = Vec::with_capacity(n * vec.len());
    for _ in 0..n {
        rv.extend_from_slice(&vec[0..vec.len()]);
    }
    return rv;
}

fn num_at(vec: &Vec<i32>, idx: usize, len: usize) -> i32 {
    let mut rv = 0;
    for i in 0..len {
        rv = 10*rv + vec[idx + i];
    }
    return rv;
}

fn load(fname: &str) -> Vec<i32> {
    let contents = fs::read_to_string(fname)
        .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));
    return contents.trim().chars().map(|c| c.to_digit(10).unwrap_or_else(|| panic!("Parse error")) as i32).collect();
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 16")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("16.in");
    let vec = load(&fname);
    println!("Part 1: {}", num_at(&fft(&vec, &PAT1, 100, 0), 0, 8));

    //    first 7 bits: 5973181
    // repeated length: 6500000
    // Thus, the "pattern" never applies to the relevant tail. Just the
    // +1's, but we MUST get the offset exactly right.
    let mut vec2 = repeat(&vec, 10000);
    let offset = num_at(&vec, 0, 7) as usize;
    let tail = vec2.split_off(offset);
    println!("Part 2: {}", fft_tail(&tail, 100, 8));
}

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

    #[test]
    fn example1() {
        assert_eq!(fft(&vec![1,2,3,4,5,6,7,8], &PAT1, 1, 0), vec![4,8,2,2,6,1,5,8]);
        assert_eq!(fft(&vec![4,8,2,2,6,1,5,8], &PAT1, 1, 0), vec![3,4,0,4,0,4,3,8]);
        assert_eq!(fft(&vec![3,4,0,4,0,4,3,8], &PAT1, 1, 0), vec![0,3,4,1,5,5,1,8]);
        assert_eq!(fft(&vec![0,3,4,1,5,5,1,8], &PAT1, 1, 0), vec![0,1,0,2,9,4,9,8]);
        assert_eq!(fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0,8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100, 0)[0..8], [2,4,1,7,6,1,7,6]);
        assert_eq!(fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9,1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100, 0)[0..8], [7,3,7,4,5,4,1,8]);
        assert_eq!(fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9,9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100, 0)[0..8], [5,2,4,3,2,1,3,3]);
        assert_eq!(num_at(&vec![9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0], 7, 8), 21098765);
    }

    #[test]
    fn tails() {
        assert_eq!(fft(&vec![5,6,7,8], &PAT1, 1, 4), vec![6,1,5,8]);
        assert_eq!(fft(&vec![6,1,5,8], &PAT1, 1, 4), vec![0,4,3,8]);
        assert_eq!(fft(&vec![0,4,3,8], &PAT1, 1, 4), vec![5,5,1,8]);
        assert_eq!(fft(&vec![5,5,1,8], &PAT1, 1, 4), vec![9,4,9,8]);

        assert_eq!(num_at(&fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0, 8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100, 0), 21, 8), fft_tail(&vec![8,3,2,1,8,6,4,5,5,9,5], 100, 8));
        assert_eq!(num_at(&fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9, 1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100, 0), 21, 8), fft_tail(&vec![1,6,0,4,4,1,8,9,9,1,7], 100, 8));
        assert_eq!(num_at(&fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9, 9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100, 0), 21, 8), fft_tail(&vec![9,5,9,2,4,3,1,9,8,7,3], 100, 8));
    }
}
<|endoftext|>


<commit_before>//! The `select` macro.

use proc_macro_hack::proc_macro_hack;

macro_rules! document_select_macro {
    // This branch is required for `futures 0.3.1`, from before select_biased was introduced
    ($select:item) => {
        /// Polls multiple futures and streams simultaneously, executing the branch
        /// for the future that finishes first. If multiple futures are ready,
        /// one will be pseudo-randomly selected at runtime. Futures directly
        /// passed to `select!` must be `Unpin` and implement `FusedFuture`.
        ///
        /// If an expression which yields a `Future` is passed to `select!`
        /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin`
        /// requirement is relaxed, since the macro will pin the resulting `Future`
        /// on the stack. However the `Future` returned by the expression must
        /// still implement `FusedFuture`. This difference is presented
        ///
        /// Futures and streams which are not already fused can be fused using the
        /// `.fuse()` method. Note, though, that fusing a future or stream directly
        /// in the call to `select!` will not be enough to prevent it from being
        /// polled after completion if the `select!` call is in a loop, so when
        /// `select!`ing in a loop, users should take care to `fuse()` outside of
        /// the loop.
        ///
        /// `select!` can be used as an expression and will return the return
        /// value of the selected branch. For this reason the return type of every
        /// branch in a `select!` must be the same.
        ///
        /// This macro is only usable inside of async functions, closures, and blocks.
        /// It is also gated behind the `async-await` feature of this library, which is
        /// activated by default.
        ///
        /// Note that `select!` relies on `proc-macro-hack`, and may require to set the
        /// compiler's recursion limit very high, e.g. `#![recursion_limit="1024"]`.
        ///
        /// # Examples
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a = future::ready(4);
        /// let mut b = future::pending::<()>();
        ///
        /// let res = select! {
        ///     a_res = a => a_res + 1,
        ///     _ = b => 0,
        /// };
        /// assert_eq!(res, 5);
        /// # });
        /// ```
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::stream::{self, StreamExt};
        /// use futures::select;
        /// let mut st = stream::iter(vec![2]).fuse();
        /// let mut fut = future::pending::<()>();
        ///
        /// select! {
        ///     x = st.next() => assert_eq!(Some(2), x),
        ///     _ = fut => panic!(),
        /// };
        /// # });
        /// ```
        ///
        /// As described earlier, `select` can directly select on expressions
        /// which return `Future`s - even if those do not implement `Unpin`:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let res = select! {
        ///     a_res = async_identity_fn(62).fuse() => a_res + 1,
        ///     b_res = async_identity_fn(13).fuse() => b_res,
        /// };
        /// assert!(res == 63 || res == 12);
        /// # });
        /// ```
        ///
        /// If a similar async function is called outside of `select` to produce
        /// a `Future`, the `Future` must be pinned in order to be able to pass
        /// it to `select`. This can be achieved via `Box::pin` for pinning a
        /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future`
        /// on the stack.
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        /// use futures::pin_mut;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let fut_1 = async_identity_fn(1).fuse();
        /// let fut_2 = async_identity_fn(2).fuse();
        /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
        /// pin_mut!(fut_2); // Pins the Future on the stack
        ///
        /// let res = select! {
        ///     a_res = fut_1 => a_res,
        ///     b_res = fut_2 => b_res,
        /// };
        /// assert!(res == 1 || res == 2);
        /// # });
        /// ```
        ///
        /// `select` also accepts a `complete` branch and a `default` branch.
        /// `complete` will run if all futures and streams have already been
        /// exhausted. `default` will run if no futures or streams are
        /// immediately ready. `complete` takes priority over `default` in
        /// the case where all futures have completed.
        /// A motivating use-case for passing `Future`s by name as well as for
        /// `complete` blocks is to call `select!` in a loop, which is
        /// demonstrated in the following example:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a_fut = future::ready(4);
        /// let mut b_fut = future::ready(6);
        /// let mut total = 0;
        ///
        /// loop {
        ///     select! {
        ///         a = a_fut => total += a,
        ///         b = b_fut => total += b,
        ///         complete => break,
        ///         default => panic!(), // never runs (futures run first, then complete)
        ///     };
        /// }
        /// assert_eq!(total, 10);
        /// # });
        /// ```
        ///
        /// Note that the futures that have been matched over can still be mutated
        /// from inside the `select!` block's branches. This can be used to implement
        /// more complex behavior such as timer resets or writing into the head of
        /// a stream.
        $select
    };

    ($select:item $select_biased:item) => {
        document_select_macro!($select);

        /// Polls multiple futures and streams simultaneously, executing the branch
        /// for the future that finishes first. Unlike [`select!`], if multiple futures are ready,
        /// one will be selected in order of declaration. Futures directly
        /// passed to `select_biased!` must be `Unpin` and implement `FusedFuture`.
        ///
        /// If an expression which yields a `Future` is passed to `select_biased!`
        /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin`
        /// requirement is relaxed, since the macro will pin the resulting `Future`
        /// on the stack. However the `Future` returned by the expression must
        /// still implement `FusedFuture`. This difference is presented
        ///
        /// Futures and streams which are not already fused can be fused using the
        /// `.fuse()` method. Note, though, that fusing a future or stream directly
        /// in the call to `select_biased!` will not be enough to prevent it from being
        /// polled after completion if the `select_biased!` call is in a loop, so when
        /// `select_biased!`ing in a loop, users should take care to `fuse()` outside of
        /// the loop.
        ///
        /// `select_biased!` can be used as an expression and will return the return
        /// value of the selected branch. For this reason the return type of every
        /// branch in a `select_biased!` must be the same.
        ///
        /// This macro is only usable inside of async functions, closures, and blocks.
        /// It is also gated behind the `async-await` feature of this library, which is
        /// activated by default.
        ///
        /// # Examples
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select_biased;
        /// let mut a = future::ready(4);
        /// let mut b = future::pending::<()>();
        ///
        /// let res = select_biased! {
        ///     a_res = a => a_res + 1,
        ///     _ = b => 0,
        /// };
        /// assert_eq!(res, 5);
        /// # });
        /// ```
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::stream::{self, StreamExt};
        /// use futures::select_biased;
        /// let mut st = stream::iter(vec![2]).fuse();
        /// let mut fut = future::pending::<()>();
        ///
        /// select_biased! {
        ///     x = st.next() => assert_eq!(Some(2), x),
        ///     _ = fut => panic!(),
        /// };
        /// # });
        /// ```
        ///
        /// As described earlier, `select_biased` can directly select on expressions
        /// which return `Future`s - even if those do not implement `Unpin`:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select_biased;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let res = select_biased! {
        ///     a_res = async_identity_fn(62).fuse() => a_res + 1,
        ///     b_res = async_identity_fn(13).fuse() => b_res,
        /// };
        /// assert!(res == 63 || res == 12);
        /// # });
        /// ```
        ///
        /// If a similar async function is called outside of `select_biased` to produce
        /// a `Future`, the `Future` must be pinned in order to be able to pass
        /// it to `select_biased`. This can be achieved via `Box::pin` for pinning a
        /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future`
        /// on the stack.
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select_biased;
        /// use futures::pin_mut;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let fut_1 = async_identity_fn(1).fuse();
        /// let fut_2 = async_identity_fn(2).fuse();
        /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
        /// pin_mut!(fut_2); // Pins the Future on the stack
        ///
        /// let res = select_biased! {
        ///     a_res = fut_1 => a_res,
        ///     b_res = fut_2 => b_res,
        /// };
        /// assert!(res == 1 || res == 2);
        /// # });
        /// ```
        ///
        /// `select_biased` also accepts a `complete` branch and a `default` branch.
        /// `complete` will run if all futures and streams have already been
        /// exhausted. `default` will run if no futures or streams are
        /// immediately ready. `complete` takes priority over `default` in
        /// the case where all futures have completed.
        /// A motivating use-case for passing `Future`s by name as well as for
        /// `complete` blocks is to call `select_biased!` in a loop, which is
        /// demonstrated in the following example:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select_biased;
        /// let mut a_fut = future::ready(4);
        /// let mut b_fut = future::ready(6);
        /// let mut total = 0;
        ///
        /// loop {
        ///     select_biased! {
        ///         a = a_fut => total += a,
        ///         b = b_fut => total += b,
        ///         complete => break,
        ///         default => panic!(), // never runs (futures run first, then complete)
        ///     };
        /// }
        /// assert_eq!(total, 10);
        /// # });
        /// ```
        ///
        /// Note that the futures that have been matched over can still be mutated
        /// from inside the `select_biased!` block's branches. This can be used to implement
        /// more complex behavior such as timer resets or writing into the head of
        /// a stream.
        ///
        /// [`select!`]: macro.select.html
        $select_biased
    };
}

#[cfg(feature = "std")]
#[doc(hidden)]
#[proc_macro_hack(support_nested)]
pub use futures_macro::select_internal;

#[doc(hidden)]
#[proc_macro_hack(support_nested)]
pub use futures_macro::select_biased_internal;

document_select_macro! {
    #[cfg(feature = "std")]
    #[macro_export]
    macro_rules! select {
        ($($tokens:tt)*) => {{
            use $crate::__reexport as __futures_crate;
            $crate::select_internal! {
                $( $tokens )*
            }
        }}
    }

    #[macro_export]
    macro_rules! select_biased {
        ($($tokens:tt)*) => {{
            use $crate::__reexport as __futures_crate;
            $crate::select_biased_internal! {
                $( $tokens )*
            }
        }}
    }
}
<commit_msg>Fix assert condition in select! example (#2196)<commit_after>//! The `select` macro.

use proc_macro_hack::proc_macro_hack;

macro_rules! document_select_macro {
    // This branch is required for `futures 0.3.1`, from before select_biased was introduced
    ($select:item) => {
        /// Polls multiple futures and streams simultaneously, executing the branch
        /// for the future that finishes first. If multiple futures are ready,
        /// one will be pseudo-randomly selected at runtime. Futures directly
        /// passed to `select!` must be `Unpin` and implement `FusedFuture`.
        ///
        /// If an expression which yields a `Future` is passed to `select!`
        /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin`
        /// requirement is relaxed, since the macro will pin the resulting `Future`
        /// on the stack. However the `Future` returned by the expression must
        /// still implement `FusedFuture`. This difference is presented
        ///
        /// Futures and streams which are not already fused can be fused using the
        /// `.fuse()` method. Note, though, that fusing a future or stream directly
        /// in the call to `select!` will not be enough to prevent it from being
        /// polled after completion if the `select!` call is in a loop, so when
        /// `select!`ing in a loop, users should take care to `fuse()` outside of
        /// the loop.
        ///
        /// `select!` can be used as an expression and will return the return
        /// value of the selected branch. For this reason the return type of every
        /// branch in a `select!` must be the same.
        ///
        /// This macro is only usable inside of async functions, closures, and blocks.
        /// It is also gated behind the `async-await` feature of this library, which is
        /// activated by default.
        ///
        /// Note that `select!` relies on `proc-macro-hack`, and may require to set the
        /// compiler's recursion limit very high, e.g. `#![recursion_limit="1024"]`.
        ///
        /// # Examples
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a = future::ready(4);
        /// let mut b = future::pending::<()>();
        ///
        /// let res = select! {
        ///     a_res = a => a_res + 1,
        ///     _ = b => 0,
        /// };
        /// assert_eq!(res, 5);
        /// # });
        /// ```
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::stream::{self, StreamExt};
        /// use futures::select;
        /// let mut st = stream::iter(vec![2]).fuse();
        /// let mut fut = future::pending::<()>();
        ///
        /// select! {
        ///     x = st.next() => assert_eq!(Some(2), x),
        ///     _ = fut => panic!(),
        /// };
        /// # });
        /// ```
        ///
        /// As described earlier, `select` can directly select on expressions
        /// which return `Future`s - even if those do not implement `Unpin`:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let res = select! {
        ///     a_res = async_identity_fn(62).fuse() => a_res + 1,
        ///     b_res = async_identity_fn(13).fuse() => b_res,
        /// };
        /// assert!(res == 63 || res == 13);
        /// # });
        /// ```
        ///
        /// If a similar async function is called outside of `select` to produce
        /// a `Future`, the `Future` must be pinned in order to be able to pass
        /// it to `select`. This can be achieved via `Box::pin` for pinning a
        /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future`
        /// on the stack.
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select;
        /// use futures::pin_mut;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let fut_1 = async_identity_fn(1).fuse();
        /// let fut_2 = async_identity_fn(2).fuse();
        /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
        /// pin_mut!(fut_2); // Pins the Future on the stack
        ///
        /// let res = select! {
        ///     a_res = fut_1 => a_res,
        ///     b_res = fut_2 => b_res,
        /// };
        /// assert!(res == 1 || res == 2);
        /// # });
        /// ```
        ///
        /// `select` also accepts a `complete` branch and a `default` branch.
        /// `complete` will run if all futures and streams have already been
        /// exhausted. `default` will run if no futures or streams are
        /// immediately ready. `complete` takes priority over `default` in
        /// the case where all futures have completed.
        /// A motivating use-case for passing `Future`s by name as well as for
        /// `complete` blocks is to call `select!` in a loop, which is
        /// demonstrated in the following example:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select;
        /// let mut a_fut = future::ready(4);
        /// let mut b_fut = future::ready(6);
        /// let mut total = 0;
        ///
        /// loop {
        ///     select! {
        ///         a = a_fut => total += a,
        ///         b = b_fut => total += b,
        ///         complete => break,
        ///         default => panic!(), // never runs (futures run first, then complete)
        ///     };
        /// }
        /// assert_eq!(total, 10);
        /// # });
        /// ```
        ///
        /// Note that the futures that have been matched over can still be mutated
        /// from inside the `select!` block's branches. This can be used to implement
        /// more complex behavior such as timer resets or writing into the head of
        /// a stream.
        $select
    };

    ($select:item $select_biased:item) => {
        document_select_macro!($select);

        /// Polls multiple futures and streams simultaneously, executing the branch
        /// for the future that finishes first. Unlike [`select!`], if multiple futures are ready,
        /// one will be selected in order of declaration. Futures directly
        /// passed to `select_biased!` must be `Unpin` and implement `FusedFuture`.
        ///
        /// If an expression which yields a `Future` is passed to `select_biased!`
        /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin`
        /// requirement is relaxed, since the macro will pin the resulting `Future`
        /// on the stack. However the `Future` returned by the expression must
        /// still implement `FusedFuture`. This difference is presented
        ///
        /// Futures and streams which are not already fused can be fused using the
        /// `.fuse()` method. Note, though, that fusing a future or stream directly
        /// in the call to `select_biased!` will not be enough to prevent it from being
        /// polled after completion if the `select_biased!` call is in a loop, so when
        /// `select_biased!`ing in a loop, users should take care to `fuse()` outside of
        /// the loop.
        ///
        /// `select_biased!` can be used as an expression and will return the return
        /// value of the selected branch. For this reason the return type of every
        /// branch in a `select_biased!` must be the same.
        ///
        /// This macro is only usable inside of async functions, closures, and blocks.
        /// It is also gated behind the `async-await` feature of this library, which is
        /// activated by default.
        ///
        /// # Examples
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select_biased;
        /// let mut a = future::ready(4);
        /// let mut b = future::pending::<()>();
        ///
        /// let res = select_biased! {
        ///     a_res = a => a_res + 1,
        ///     _ = b => 0,
        /// };
        /// assert_eq!(res, 5);
        /// # });
        /// ```
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::stream::{self, StreamExt};
        /// use futures::select_biased;
        /// let mut st = stream::iter(vec![2]).fuse();
        /// let mut fut = future::pending::<()>();
        ///
        /// select_biased! {
        ///     x = st.next() => assert_eq!(Some(2), x),
        ///     _ = fut => panic!(),
        /// };
        /// # });
        /// ```
        ///
        /// As described earlier, `select_biased` can directly select on expressions
        /// which return `Future`s - even if those do not implement `Unpin`:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select_biased;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let res = select_biased! {
        ///     a_res = async_identity_fn(62).fuse() => a_res + 1,
        ///     b_res = async_identity_fn(13).fuse() => b_res,
        /// };
        /// assert!(res == 63 || res == 12);
        /// # });
        /// ```
        ///
        /// If a similar async function is called outside of `select_biased` to produce
        /// a `Future`, the `Future` must be pinned in order to be able to pass
        /// it to `select_biased`. This can be achieved via `Box::pin` for pinning a
        /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future`
        /// on the stack.
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future::FutureExt;
        /// use futures::select_biased;
        /// use futures::pin_mut;
        ///
        /// // Calling the following async fn returns a Future which does not
        /// // implement Unpin
        /// async fn async_identity_fn(arg: usize) -> usize {
        ///     arg
        /// }
        ///
        /// let fut_1 = async_identity_fn(1).fuse();
        /// let fut_2 = async_identity_fn(2).fuse();
        /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
        /// pin_mut!(fut_2); // Pins the Future on the stack
        ///
        /// let res = select_biased! {
        ///     a_res = fut_1 => a_res,
        ///     b_res = fut_2 => b_res,
        /// };
        /// assert!(res == 1 || res == 2);
        /// # });
        /// ```
        ///
        /// `select_biased` also accepts a `complete` branch and a `default` branch.
        /// `complete` will run if all futures and streams have already been
        /// exhausted. `default` will run if no futures or streams are
        /// immediately ready. `complete` takes priority over `default` in
        /// the case where all futures have completed.
        /// A motivating use-case for passing `Future`s by name as well as for
        /// `complete` blocks is to call `select_biased!` in a loop, which is
        /// demonstrated in the following example:
        ///
        /// ```
        /// # futures::executor::block_on(async {
        /// use futures::future;
        /// use futures::select_biased;
        /// let mut a_fut = future::ready(4);
        /// let mut b_fut = future::ready(6);
        /// let mut total = 0;
        ///
        /// loop {
        ///     select_biased! {
        ///         a = a_fut => total += a,
        ///         b = b_fut => total += b,
        ///         complete => break,
        ///         default => panic!(), // never runs (futures run first, then complete)
        ///     };
        /// }
        /// assert_eq!(total, 10);
        /// # });
        /// ```
        ///
        /// Note that the futures that have been matched over can still be mutated
        /// from inside the `select_biased!` block's branches. This can be used to implement
        /// more complex behavior such as timer resets or writing into the head of
        /// a stream.
        ///
        /// [`select!`]: macro.select.html
        $select_biased
    };
}

#[cfg(feature = "std")]
#[doc(hidden)]
#[proc_macro_hack(support_nested)]
pub use futures_macro::select_internal;

#[doc(hidden)]
#[proc_macro_hack(support_nested)]
pub use futures_macro::select_biased_internal;

document_select_macro! {
    #[cfg(feature = "std")]
    #[macro_export]
    macro_rules! select {
        ($($tokens:tt)*) => {{
            use $crate::__reexport as __futures_crate;
            $crate::select_internal! {
                $( $tokens )*
            }
        }}
    }

    #[macro_export]
    macro_rules! select_biased {
        ($($tokens:tt)*) => {{
            use $crate::__reexport as __futures_crate;
            $crate::select_biased_internal! {
                $( $tokens )*
            }
        }}
    }
}
<|endoftext|>


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

use std::collections::HashSet;
use std::os;
use std::io::IoError;
use syntax::abi;
use syntax::ast;

pub struct RPathConfig<'a> {
    pub os: abi::Os,
    pub used_crates: Vec<(ast::CrateNum, Option<Path>)>,
    pub out_filename: Path,
    pub get_install_prefix_lib_path: ||:'a -> Path,
    pub realpath: |&Path|:'a -> Result<Path, IoError>
}

pub fn get_rpath_flags(config: RPathConfig) -> Vec<String> {

    // No rpath on windows
    if config.os == abi::OsWindows {
        return Vec::new();
    }

    let mut flags = Vec::new();

    if config.os == abi::OsFreebsd {
        flags.push_all(["-Wl,-rpath,/usr/local/lib/gcc46".to_string(),
                        "-Wl,-rpath,/usr/local/lib/gcc44".to_string(),
                        "-Wl,-z,origin".to_string()]);
    }
    else if config.os == abi::OsDragonfly {
        flags.push_all(["-Wl,-rpath,/usr/lib/gcc47".to_string(),
                        "-Wl,-rpath,/usr/lib/gcc44".to_string(),
                        "-Wl,-z,origin".to_string()]);
    }

    debug!("preparing the RPATH!");

    let libs = config.used_crates.clone();
    let libs = libs.into_iter().filter_map(|(_, l)| {
        l.map(|p| p.clone())
    }).collect::<Vec<_>>();

    let rpaths = get_rpaths(config, libs.as_slice());
    flags.push_all(rpaths_to_flags(rpaths.as_slice()).as_slice());
    flags
}

fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
    let mut ret = Vec::new();
    for rpath in rpaths.iter() {
        ret.push(format!("-Wl,-rpath,{}", (*rpath).as_slice()));
    }
    return ret;
}

fn get_rpaths(mut config: RPathConfig,
              libs: &[Path]) -> Vec<String> {
    debug!("output: {}", config.out_filename.display());
    debug!("libs:");
    for libpath in libs.iter() {
        debug!("    {}", libpath.display());
    }

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(&mut config, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = vec!(get_install_prefix_rpath(config));

    fn log_rpaths(desc: &str, rpaths: &[String]) {
        debug!("{} rpaths:", desc);
        for rpath in rpaths.iter() {
            debug!("    {}", *rpath);
        }
    }

    log_rpaths("relative", rel_rpaths.as_slice());
    log_rpaths("fallback", fallback_rpaths.as_slice());

    let mut rpaths = rel_rpaths;
    rpaths.push_all(fallback_rpaths.as_slice());

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths.as_slice());
    return rpaths;
}

fn get_rpaths_relative_to_output(config: &mut RPathConfig,
                                 libs: &[Path]) -> Vec<String> {
    libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
}

fn get_rpath_relative_to_output(config: &mut RPathConfig,
                                lib: &Path) -> String {
    use std::os;

    assert!(config.os != abi::OsWindows);

    // Mac doesn't appear to support $ORIGIN
    let prefix = match config.os {
        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd | abi::OsDragonfly
                          => "$ORIGIN",
        abi::OsMacos => "@loader_path",
        abi::OsWindows | abi::OsiOS => unreachable!()
    };

    let mut lib = (config.realpath)(&os::make_absolute(lib)).unwrap();
    lib.pop();
    let mut output = (config.realpath)(&os::make_absolute(&config.out_filename)).unwrap();
    output.pop();
    let relative = lib.path_relative_from(&output);
    let relative = relative.expect("could not create rpath relative to output");
    // FIXME (#9639): This needs to handle non-utf8 paths
    format!("{}/{}",
            prefix,
            relative.as_str().expect("non-utf8 component in path"))
}

fn get_install_prefix_rpath(config: RPathConfig) -> String {
    let path = (config.get_install_prefix_lib_path)();
    let path = os::make_absolute(&path);
    // FIXME (#9639): This needs to handle non-utf8 paths
    path.as_str().expect("non-utf8 component in rpath").to_string()
}

fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
    let mut set = HashSet::new();
    let mut minimized = Vec::new();
    for rpath in rpaths.iter() {
        if set.insert(rpath.as_slice()) {
            minimized.push(rpath.clone());
        }
    }
    minimized
}

#[cfg(all(unix, test))]
mod test {
    use super::{RPathConfig};
    use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
    use syntax::abi;

    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags([
            "path1".to_string(),
            "path2".to_string()
        ]);
        assert_eq!(flags,
                   vec!("-Wl,-rpath,path1".to_string(),
                        "-Wl,-rpath,path2".to_string()));
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths([
            "rpath1".to_string(),
            "rpath2".to_string(),
            "rpath1".to_string()
        ]);
        assert!(res.as_slice() == [
            "rpath1".to_string(),
            "rpath2".to_string()
        ]);
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths([
            "1a".to_string(),
            "2".to_string(),
            "2".to_string(),
            "1a".to_string(),
            "4a".to_string(),
            "1a".to_string(),
            "2".to_string(),
            "3".to_string(),
            "4a".to_string(),
            "3".to_string()
        ]);
        assert!(res.as_slice() == [
            "1a".to_string(),
            "2".to_string(),
            "4a".to_string(),
            "3".to_string()
        ]);
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "android")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsLinux,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsFreebsd,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "dragonfly")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsDragonfly,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsMacos,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "@loader_path/../lib");
    }
}
<commit_msg>Fix cfg warnings in librustc_back<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashSet;
use std::os;
use std::io::IoError;
use syntax::abi;
use syntax::ast;

pub struct RPathConfig<'a> {
    pub os: abi::Os,
    pub used_crates: Vec<(ast::CrateNum, Option<Path>)>,
    pub out_filename: Path,
    pub get_install_prefix_lib_path: ||:'a -> Path,
    pub realpath: |&Path|:'a -> Result<Path, IoError>
}

pub fn get_rpath_flags(config: RPathConfig) -> Vec<String> {

    // No rpath on windows
    if config.os == abi::OsWindows {
        return Vec::new();
    }

    let mut flags = Vec::new();

    if config.os == abi::OsFreebsd {
        flags.push_all(["-Wl,-rpath,/usr/local/lib/gcc46".to_string(),
                        "-Wl,-rpath,/usr/local/lib/gcc44".to_string(),
                        "-Wl,-z,origin".to_string()]);
    }
    else if config.os == abi::OsDragonfly {
        flags.push_all(["-Wl,-rpath,/usr/lib/gcc47".to_string(),
                        "-Wl,-rpath,/usr/lib/gcc44".to_string(),
                        "-Wl,-z,origin".to_string()]);
    }

    debug!("preparing the RPATH!");

    let libs = config.used_crates.clone();
    let libs = libs.into_iter().filter_map(|(_, l)| {
        l.map(|p| p.clone())
    }).collect::<Vec<_>>();

    let rpaths = get_rpaths(config, libs.as_slice());
    flags.push_all(rpaths_to_flags(rpaths.as_slice()).as_slice());
    flags
}

fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
    let mut ret = Vec::new();
    for rpath in rpaths.iter() {
        ret.push(format!("-Wl,-rpath,{}", (*rpath).as_slice()));
    }
    return ret;
}

fn get_rpaths(mut config: RPathConfig,
              libs: &[Path]) -> Vec<String> {
    debug!("output: {}", config.out_filename.display());
    debug!("libs:");
    for libpath in libs.iter() {
        debug!("    {}", libpath.display());
    }

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(&mut config, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = vec!(get_install_prefix_rpath(config));

    fn log_rpaths(desc: &str, rpaths: &[String]) {
        debug!("{} rpaths:", desc);
        for rpath in rpaths.iter() {
            debug!("    {}", *rpath);
        }
    }

    log_rpaths("relative", rel_rpaths.as_slice());
    log_rpaths("fallback", fallback_rpaths.as_slice());

    let mut rpaths = rel_rpaths;
    rpaths.push_all(fallback_rpaths.as_slice());

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths.as_slice());
    return rpaths;
}

fn get_rpaths_relative_to_output(config: &mut RPathConfig,
                                 libs: &[Path]) -> Vec<String> {
    libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
}

fn get_rpath_relative_to_output(config: &mut RPathConfig,
                                lib: &Path) -> String {
    use std::os;

    assert!(config.os != abi::OsWindows);

    // Mac doesn't appear to support $ORIGIN
    let prefix = match config.os {
        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd | abi::OsDragonfly
                          => "$ORIGIN",
        abi::OsMacos => "@loader_path",
        abi::OsWindows | abi::OsiOS => unreachable!()
    };

    let mut lib = (config.realpath)(&os::make_absolute(lib)).unwrap();
    lib.pop();
    let mut output = (config.realpath)(&os::make_absolute(&config.out_filename)).unwrap();
    output.pop();
    let relative = lib.path_relative_from(&output);
    let relative = relative.expect("could not create rpath relative to output");
    // FIXME (#9639): This needs to handle non-utf8 paths
    format!("{}/{}",
            prefix,
            relative.as_str().expect("non-utf8 component in path"))
}

fn get_install_prefix_rpath(config: RPathConfig) -> String {
    let path = (config.get_install_prefix_lib_path)();
    let path = os::make_absolute(&path);
    // FIXME (#9639): This needs to handle non-utf8 paths
    path.as_str().expect("non-utf8 component in rpath").to_string()
}

fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
    let mut set = HashSet::new();
    let mut minimized = Vec::new();
    for rpath in rpaths.iter() {
        if set.insert(rpath.as_slice()) {
            minimized.push(rpath.clone());
        }
    }
    minimized
}

#[cfg(all(unix, test))]
mod test {
    use super::{RPathConfig};
    use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
    use syntax::abi;

    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags([
            "path1".to_string(),
            "path2".to_string()
        ]);
        assert_eq!(flags,
                   vec!("-Wl,-rpath,path1".to_string(),
                        "-Wl,-rpath,path2".to_string()));
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths([
            "rpath1".to_string(),
            "rpath2".to_string(),
            "rpath1".to_string()
        ]);
        assert!(res.as_slice() == [
            "rpath1".to_string(),
            "rpath2".to_string()
        ]);
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths([
            "1a".to_string(),
            "2".to_string(),
            "2".to_string(),
            "1a".to_string(),
            "4a".to_string(),
            "1a".to_string(),
            "2".to_string(),
            "3".to_string(),
            "4a".to_string(),
            "3".to_string()
        ]);
        assert!(res.as_slice() == [
            "1a".to_string(),
            "2".to_string(),
            "4a".to_string(),
            "3".to_string()
        ]);
    }

    #[test]
    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsLinux,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsFreebsd,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "dragonfly")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsDragonfly,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let config = &mut RPathConfig {
            os: abi::OsMacos,
            used_crates: Vec::new(),
            out_filename: Path::new("bin/rustc"),
            get_install_prefix_lib_path: || fail!(),
            realpath: |p| Ok(p.clone())
        };
        let res = get_rpath_relative_to_output(config, &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "@loader_path/../lib");
    }
}
<|endoftext|>


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

#![crate_name = "alloc_system"]
#![crate_type = "rlib"]
#![no_std]
#![allocator]
#![cfg_attr(not(stage0), deny(warnings))]
#![unstable(feature = "alloc_system",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![feature(allocator)]
#![feature(staged_api)]
#![cfg_attr(unix, feature(libc))]

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "powerpc",
              target_arch = "powerpc64",
              target_arch = "asmjs")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
              target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe { imp::allocate(size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
    unsafe { imp::deallocate(ptr, old_size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    old_size: usize,
                                    size: usize,
                                    align: usize)
                                    -> *mut u8 {
    unsafe { imp::reallocate(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
                                            old_size: usize,
                                            size: usize,
                                            align: usize)
                                            -> usize {
    unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
    imp::usable_size(size, align)
}

#[cfg(unix)]
mod imp {
    extern crate libc;

    use core::cmp;
    use core::ptr;
    use MIN_ALIGN;

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::malloc(size as libc::size_t) as *mut u8
        } else {
            let mut out = ptr::null_mut();
            let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
            if ret != 0 {
                ptr::null_mut()
            } else {
                out as *mut u8
            }
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
        } else {
            let new_ptr = allocate(size, align);
            if !new_ptr.is_null() {
                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
                deallocate(ptr, old_size, align);
            }
            new_ptr
        }
    }

    pub unsafe fn reallocate_inplace(_ptr: *mut u8,
                                     old_size: usize,
                                     _size: usize,
                                     _align: usize)
                                     -> usize {
        old_size
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
        libc::free(ptr as *mut libc::c_void)
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}

#[cfg(windows)]
#[allow(bad_style)]
mod imp {
    use MIN_ALIGN;

    type LPVOID = *mut u8;
    type HANDLE = LPVOID;
    type SIZE_T = usize;
    type DWORD = u32;
    type BOOL = i32;

    extern "system" {
        fn GetProcessHeap() -> HANDLE;
        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
    }

    #[repr(C)]
    struct Header(*mut u8);

    const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;

    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
        &mut *(ptr as *mut Header).offset(-1)
    }

    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
        let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
        *get_header(aligned) = Header(ptr);
        aligned
    }

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
        } else {
            let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
            if ptr.is_null() {
                return ptr;
            }
            align_ptr(ptr, align)
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
        } else {
            let header = get_header(ptr);
            let new = HeapReAlloc(GetProcessHeap(),
                                  0,
                                  header.0 as LPVOID,
                                  (size + align) as SIZE_T) as *mut u8;
            if new.is_null() {
                return new;
            }
            align_ptr(new, align)
        }
    }

    pub unsafe fn reallocate_inplace(ptr: *mut u8,
                                     old_size: usize,
                                     size: usize,
                                     align: usize)
                                     -> usize {
        if align <= MIN_ALIGN {
            let new = HeapReAlloc(GetProcessHeap(),
                                  HEAP_REALLOC_IN_PLACE_ONLY,
                                  ptr as LPVOID,
                                  size as SIZE_T) as *mut u8;
            if new.is_null() {
                old_size
            } else {
                size
            }
        } else {
            old_size
        }
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
        if align <= MIN_ALIGN {
            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
            debug_assert!(err != 0);
        } else {
            let header = get_header(ptr);
            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
            debug_assert!(err != 0);
        }
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}
<commit_msg>std: Use memalign, not posix_memalign, on Android<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "alloc_system"]
#![crate_type = "rlib"]
#![no_std]
#![allocator]
#![cfg_attr(not(stage0), deny(warnings))]
#![unstable(feature = "alloc_system",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![feature(allocator)]
#![feature(staged_api)]
#![cfg_attr(unix, feature(libc))]

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "powerpc",
              target_arch = "powerpc64",
              target_arch = "asmjs")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
              target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe { imp::allocate(size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
    unsafe { imp::deallocate(ptr, old_size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    old_size: usize,
                                    size: usize,
                                    align: usize)
                                    -> *mut u8 {
    unsafe { imp::reallocate(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
                                            old_size: usize,
                                            size: usize,
                                            align: usize)
                                            -> usize {
    unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
    imp::usable_size(size, align)
}

#[cfg(unix)]
mod imp {
    extern crate libc;

    use core::cmp;
    use core::ptr;
    use MIN_ALIGN;

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::malloc(size as libc::size_t) as *mut u8
        } else {
            aligned_malloc(size, align)
        }
    }

    #[cfg(target_os = "android")]
    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
        // On android we currently target API level 9 which unfortunately
        // doesn't have the `posix_memalign` API used below. Instead we use
        // `memalign`, but this unfortunately has the property on some systems
        // where the memory returned cannot be deallocated by `free`!
        //
        // Upon closer inspection, however, this appears to work just fine with
        // Android, so for this platform we should be fine to call `memalign`
        // (which is present in API level 9). Some helpful references could
        // possibly be chromium using memalign [1], attempts at documenting that
        // memalign + free is ok [2] [3], or the current source of chromium
        // which still uses memalign on android [4].
        //
        // [1]: https://codereview.chromium.org/10796020/
        // [2]: https://code.google.com/p/android/issues/detail?id=35391
        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
        //                                       /memory/aligned_memory.cc
        libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
    }

    #[cfg(not(target_os = "android"))]
    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
        let mut out = ptr::null_mut();
        let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
        if ret != 0 {
            ptr::null_mut()
        } else {
            out as *mut u8
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
        } else {
            let new_ptr = allocate(size, align);
            if !new_ptr.is_null() {
                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
                deallocate(ptr, old_size, align);
            }
            new_ptr
        }
    }

    pub unsafe fn reallocate_inplace(_ptr: *mut u8,
                                     old_size: usize,
                                     _size: usize,
                                     _align: usize)
                                     -> usize {
        old_size
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
        libc::free(ptr as *mut libc::c_void)
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}

#[cfg(windows)]
#[allow(bad_style)]
mod imp {
    use MIN_ALIGN;

    type LPVOID = *mut u8;
    type HANDLE = LPVOID;
    type SIZE_T = usize;
    type DWORD = u32;
    type BOOL = i32;

    extern "system" {
        fn GetProcessHeap() -> HANDLE;
        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
    }

    #[repr(C)]
    struct Header(*mut u8);

    const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;

    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
        &mut *(ptr as *mut Header).offset(-1)
    }

    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
        let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
        *get_header(aligned) = Header(ptr);
        aligned
    }

    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
        } else {
            let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
            if ptr.is_null() {
                return ptr;
            }
            align_ptr(ptr, align)
        }
    }

    pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
        if align <= MIN_ALIGN {
            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
        } else {
            let header = get_header(ptr);
            let new = HeapReAlloc(GetProcessHeap(),
                                  0,
                                  header.0 as LPVOID,
                                  (size + align) as SIZE_T) as *mut u8;
            if new.is_null() {
                return new;
            }
            align_ptr(new, align)
        }
    }

    pub unsafe fn reallocate_inplace(ptr: *mut u8,
                                     old_size: usize,
                                     size: usize,
                                     align: usize)
                                     -> usize {
        if align <= MIN_ALIGN {
            let new = HeapReAlloc(GetProcessHeap(),
                                  HEAP_REALLOC_IN_PLACE_ONLY,
                                  ptr as LPVOID,
                                  size as SIZE_T) as *mut u8;
            if new.is_null() {
                old_size
            } else {
                size
            }
        } else {
            old_size
        }
    }

    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
        if align <= MIN_ALIGN {
            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
            debug_assert!(err != 0);
        } else {
            let header = get_header(ptr);
            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
            debug_assert!(err != 0);
        }
    }

    pub fn usable_size(size: usize, _align: usize) -> usize {
        size
    }
}
<|endoftext|>