<commit_before>use ll;
use pa;
use pa::{PaError, PaResult};
use util::{to_pa_result, pa_time_to_duration};
use std::raw::Slice;
use std::mem;
use std::time::duration::Duration;

#[repr(u32)]
pub enum StreamCallbackResult
{
    Continue = ll::paContinue,
    Complete = ll::paComplete,
    Abort = ll::paAbort,
}

pub type StreamCallback<'a, T> = |input: &[T], output: &mut [T], timeinfo: StreamTimeInfo, StreamFlags|:'a -> StreamCallbackResult;

struct StreamUserData<'a, T>
{
    num_input: uint,
    num_output: uint,
    callback: StreamCallback<'a, T>,
}

pub struct StreamTimeInfo
{
    pub input_adc_time: Duration,
    pub current_time: Duration,
    pub output_dac_time: Duration,
}

bitflags!(
    flags StreamFlags: u64 {
        static inputUnderflow = 0x01,
        static inputOverflow = 0x02,
        static outputUnderflow = 0x04,
        static outputOverflow = 0x08,
        static primingOutput = 0x10
    }
)

extern "C" fn stream_callback<T>(input: *const ::libc::c_void,
                              output: *mut ::libc::c_void,
                              frame_count: ::libc::c_ulong,
                              time_info: *const ll::PaStreamCallbackTimeInfo,
                              status_flags: ll::PaStreamCallbackFlags,
                              user_data: *mut ::libc::c_void) -> ::libc::c_int
{
    let stream_data: Box<StreamUserData<T>> = unsafe { mem::transmute(user_data) };
    let input_buffer: &[T] = unsafe
    {
        mem::transmute(
            Slice { data: input as *const T, len: frame_count as uint * stream_data.num_input }
        )
    };
    let output_buffer: &mut [T] = unsafe
    {
        mem::transmute(
            Slice { data: output as *const T, len: frame_count as uint * stream_data.num_output }
        )
    };

    let flags = StreamFlags::from_bits_truncate(status_flags);

    let timeinfo = match unsafe { time_info.to_option() }
    {
        Some(ref info) => StreamTimeInfo { input_adc_time: pa_time_to_duration(info.inputBufferAdcTime),
                                           current_time: pa_time_to_duration(info.currentTime),
                                           output_dac_time: pa_time_to_duration(info.outputBufferDacTime) },
        None => StreamTimeInfo { input_adc_time: Duration::seconds(0),
                                 current_time: Duration::seconds(0),
                                 output_dac_time: Duration::seconds(0), },
    };

    let result = (stream_data.callback)(input_buffer, output_buffer, timeinfo, flags);

    unsafe { mem::forget(stream_data); }

    result as i32
}

trait PaType { fn as_sample_format(_: Option<Self>) -> u64; }
impl PaType for f32 { fn as_sample_format(_: Option<f32>) -> u64 { 0x00000001 } }
impl PaType for i32 { fn as_sample_format(_: Option<i32>) -> u64 { 0x00000002 } }
impl PaType for i16 { fn as_sample_format(_: Option<i16>) -> u64 { 0x00000008 } }
impl PaType for i8 { fn as_sample_format(_: Option<i8>) -> u64 { 0x00000010 } }
impl PaType for u8 { fn as_sample_format(_: Option<u8>) -> u64 { 0x00000020 } }

pub struct Stream<'a, T>
{
    pa_stream: *mut ll::PaStream,
    inputs: uint,
    outputs: uint,
    _callback: Box<StreamUserData<'a, T>>,
}

impl<'a, T: PaType> Stream<'a, T>
{
    pub fn open_default_stream(num_input_channels: uint,
                               num_output_channels: uint,
                               sample_rate: f64,
                               frames_per_buffer: u64,
                               callback: StreamCallback<'a, T>)
                              -> Result<Stream<'a, T>, PaError>
    {
        unsafe
        {
            let userdata = box StreamUserData
            {
                num_input: num_input_channels,
                num_output: num_output_channels,
                callback: callback,
            };
            let mut pa_stream = ::std::ptr::mut_null();

            let ud_pointer: *mut ::libc::c_void = ::std::mem::transmute(userdata);
            let ud_pointer_2 = ud_pointer.clone();
            let code = ll::Pa_OpenDefaultStream(&mut pa_stream as *mut *mut ll::PaStream,
                                                num_input_channels as i32,
                                                num_output_channels as i32,
                                                PaType::as_sample_format(None::<T>),
                                                sample_rate,
                                                frames_per_buffer,
                                                stream_callback::<T>,
                                                ud_pointer);
            match to_pa_result(code)
            {
                Ok(()) => Ok(Stream { pa_stream: pa_stream,
                                      _callback: ::std::mem::transmute(ud_pointer_2),
                                      inputs: num_input_channels,
                                      outputs: num_output_channels,
                             }),
                Err(v) => Err(v),
            }
        }
    }

    pub fn start(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StartStream(self.pa_stream) })
    }

    pub fn stop(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StopStream(self.pa_stream) })
    }

    pub fn abort(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_AbortStream(self.pa_stream) })
    }

    fn close(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_CloseStream(self.pa_stream) })
    }

    pub fn is_stopped(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamStopped(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn is_active(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamActive(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn read_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamReadAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamWriteAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write(&self, buffer: &[T]) -> PaResult
    {
        if self.outputs == 0 { return Err(pa::CanNotWriteToAnInputOnlyStream) }

        let Slice { data, len } = unsafe { mem::transmute::<&[T], Slice<T>>(buffer) };
        let buffer = data as *const ::libc::c_void;
        let frames = (len / self.outputs) as u64;

        to_pa_result(unsafe { ll::Pa_WriteStream(self.pa_stream, buffer, frames) })
    }

    pub fn read(&self, buffer: &mut [T]) -> PaResult
    {
        if self.inputs == 0 { return Err(pa::CanNotReadFromAnOutputOnlyStream) }

        let Slice { data, len } = unsafe { mem::transmute::<&mut [T], Slice<T>>(buffer) };
        let buffer = data as *mut ::libc::c_void;
        let frames = (len / self.inputs) as u64;

        to_pa_result(unsafe { ll::Pa_ReadStream(self.pa_stream, buffer, frames) })
    }

    pub fn cpu_load(&self) -> f64
    {
        unsafe { ll::Pa_GetStreamCpuLoad(self.pa_stream) }
    }

    pub fn time(&self) -> Duration
    {
        let time = unsafe { ll::Pa_GetStreamTime(self.pa_stream) };
        pa_time_to_duration(time)
    }
}

#[unsafe_destructor]
impl<'a, T: PaType> Drop for Stream<'a, T>
{
    fn drop(&mut self)
    {
        match self.close()
        {
            Err(v) => error!("Error: {}", v),
            Ok(_) => {},
        };
    }
}
<commit_msg>Add StreamInfo<commit_after>use ll;
use pa;
use pa::{PaError, PaResult};
use device::DeviceIndex;
use util::{to_pa_result, pa_time_to_duration};
use std::raw::Slice;
use std::mem;
use std::time::duration::Duration;

#[repr(u32)]
pub enum StreamCallbackResult
{
    Continue = ll::paContinue,
    Complete = ll::paComplete,
    Abort = ll::paAbort,
}

pub type StreamCallback<'a, T> = |input: &[T], output: &mut [T], timeinfo: StreamTimeInfo, StreamFlags|:'a -> StreamCallbackResult;

struct StreamUserData<'a, T>
{
    num_input: uint,
    num_output: uint,
    callback: StreamCallback<'a, T>,
}

pub struct StreamTimeInfo
{
    pub input_adc_time: Duration,
    pub current_time: Duration,
    pub output_dac_time: Duration,
}

bitflags!(
    flags StreamFlags: u64 {
        static inputUnderflow = 0x01,
        static inputOverflow = 0x02,
        static outputUnderflow = 0x04,
        static outputOverflow = 0x08,
        static primingOutput = 0x10
    }
)

extern "C" fn stream_callback<T>(input: *const ::libc::c_void,
                              output: *mut ::libc::c_void,
                              frame_count: ::libc::c_ulong,
                              time_info: *const ll::PaStreamCallbackTimeInfo,
                              status_flags: ll::PaStreamCallbackFlags,
                              user_data: *mut ::libc::c_void) -> ::libc::c_int
{
    let stream_data: Box<StreamUserData<T>> = unsafe { mem::transmute(user_data) };
    let input_buffer: &[T] = unsafe
    {
        mem::transmute(
            Slice { data: input as *const T, len: frame_count as uint * stream_data.num_input }
        )
    };
    let output_buffer: &mut [T] = unsafe
    {
        mem::transmute(
            Slice { data: output as *const T, len: frame_count as uint * stream_data.num_output }
        )
    };

    let flags = StreamFlags::from_bits_truncate(status_flags);

    let timeinfo = match unsafe { time_info.to_option() }
    {
        Some(ref info) => StreamTimeInfo { input_adc_time: pa_time_to_duration(info.inputBufferAdcTime),
                                           current_time: pa_time_to_duration(info.currentTime),
                                           output_dac_time: pa_time_to_duration(info.outputBufferDacTime) },
        None => StreamTimeInfo { input_adc_time: Duration::seconds(0),
                                 current_time: Duration::seconds(0),
                                 output_dac_time: Duration::seconds(0), },
    };

    let result = (stream_data.callback)(input_buffer, output_buffer, timeinfo, flags);

    unsafe { mem::forget(stream_data); }

    result as i32
}

trait SampleType { fn as_sample_format(_: Option<Self>) -> u64; }
impl SampleType for f32 { fn as_sample_format(_: Option<f32>) -> u64 { 0x00000001 } }
impl SampleType for i32 { fn as_sample_format(_: Option<i32>) -> u64 { 0x00000002 } }
impl SampleType for i16 { fn as_sample_format(_: Option<i16>) -> u64 { 0x00000008 } }
impl SampleType for i8 { fn as_sample_format(_: Option<i8>) -> u64 { 0x00000010 } }
impl SampleType for u8 { fn as_sample_format(_: Option<u8>) -> u64 { 0x00000020 } }

pub struct Stream<'a, T>
{
    pa_stream: *mut ll::PaStream,
    inputs: uint,
    outputs: uint,
    _callback: Box<StreamUserData<'a, T>>,
}

impl<'a, T: SampleType> Stream<'a, T>
{
    pub fn open_default_stream(num_input_channels: uint,
                               num_output_channels: uint,
                               sample_rate: f64,
                               frames_per_buffer: u64,
                               callback: StreamCallback<'a, T>)
                              -> Result<Stream<'a, T>, PaError>
    {
        unsafe
        {
            let userdata = box StreamUserData
            {
                num_input: num_input_channels,
                num_output: num_output_channels,
                callback: callback,
            };
            let mut pa_stream = ::std::ptr::mut_null();

            let ud_pointer: *mut ::libc::c_void = ::std::mem::transmute(userdata);
            let ud_pointer_2 = ud_pointer.clone();
            let code = ll::Pa_OpenDefaultStream(&mut pa_stream as *mut *mut ll::PaStream,
                                                num_input_channels as i32,
                                                num_output_channels as i32,
                                                SampleType::as_sample_format(None::<T>),
                                                sample_rate,
                                                frames_per_buffer,
                                                stream_callback::<T>,
                                                ud_pointer);
            match to_pa_result(code)
            {
                Ok(()) => Ok(Stream { pa_stream: pa_stream,
                                      _callback: ::std::mem::transmute(ud_pointer_2),
                                      inputs: num_input_channels,
                                      outputs: num_output_channels,
                             }),
                Err(v) => Err(v),
            }
        }
    }

    pub fn start(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StartStream(self.pa_stream) })
    }

    pub fn stop(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StopStream(self.pa_stream) })
    }

    pub fn abort(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_AbortStream(self.pa_stream) })
    }

    fn close(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_CloseStream(self.pa_stream) })
    }

    pub fn is_stopped(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamStopped(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn is_active(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamActive(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn read_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamReadAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamWriteAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write(&self, buffer: &[T]) -> PaResult
    {
        if self.outputs == 0 { return Err(pa::CanNotWriteToAnInputOnlyStream) }

        let Slice { data, len } = unsafe { mem::transmute::<&[T], Slice<T>>(buffer) };
        let buffer = data as *const ::libc::c_void;
        let frames = (len / self.outputs) as u64;

        to_pa_result(unsafe { ll::Pa_WriteStream(self.pa_stream, buffer, frames) })
    }

    pub fn read(&self, buffer: &mut [T]) -> PaResult
    {
        if self.inputs == 0 { return Err(pa::CanNotReadFromAnOutputOnlyStream) }

        let Slice { data, len } = unsafe { mem::transmute::<&mut [T], Slice<T>>(buffer) };
        let buffer = data as *mut ::libc::c_void;
        let frames = (len / self.inputs) as u64;

        to_pa_result(unsafe { ll::Pa_ReadStream(self.pa_stream, buffer, frames) })
    }

    pub fn cpu_load(&self) -> f64
    {
        unsafe { ll::Pa_GetStreamCpuLoad(self.pa_stream) }
    }

    pub fn time(&self) -> Duration
    {
        let time = unsafe { ll::Pa_GetStreamTime(self.pa_stream) };
        pa_time_to_duration(time)
    }

    pub fn info(&self) -> Option<StreamInfo>
    {
        unsafe
        {
            ll::Pa_GetStreamInfo(self.pa_stream)
                .to_option()
                .map(|s| StreamInfo::from_ll(s))
        }
    }
}

#[unsafe_destructor]
impl<'a, T: SampleType> Drop for Stream<'a, T>
{
    fn drop(&mut self)
    {
        match self.close()
        {
            Err(v) => error!("Error: {}", v),
            Ok(_) => {},
        };
    }
}

pub struct StreamParameters<T>
{
    pub device: DeviceIndex,
    pub channel_count: uint,
    pub suggested_latency: Duration,
}

impl<T: SampleType> StreamParameters<T>
{
    fn to_ll(&self) -> ll::Struct_PaStreamParameters
    {
        ll::Struct_PaStreamParameters
        {
            device: self.device as i32,
            channelCount: self.channel_count as i32,
            sampleFormat: SampleType::as_sample_format(None::<T>),
            suggestedLatency: self.suggested_latency.num_milliseconds() as f64 / 1000.0,
            hostApiSpecificStreamInfo: ::std::ptr::mut_null(),
        }
    }
}

pub fn is_format_supported<I: SampleType, O: SampleType>(input: StreamParameters<I>, output: StreamParameters<O>, sample_rate: f64) -> PaResult
{
    to_pa_result(unsafe { ll::Pa_IsFormatSupported(&input.to_ll(), &output.to_ll(), sample_rate) })
}

pub struct StreamInfo
{
    pub input_latency: Duration,
    pub output_latency: Duration,
    pub sample_rate: f64,
}

impl StreamInfo
{
    fn from_ll(data: &ll::PaStreamInfo) -> StreamInfo
    {
        StreamInfo
        {
            input_latency: pa_time_to_duration(data.inputLatency),
            output_latency: pa_time_to_duration(data.outputLatency),
            sample_rate: data.sampleRate,
        }
    }
}
<|endoftext|>


<commit_before>//! Wrappers implementing `Read`, `Write`, and `Seek` for doing I/O on individual
//! RADOS objects.

use std::ffi::{CStr, CString};
use std::io::{self, SeekFrom, Read, Seek, Write};

use futures::Future;

use async::{RadosCaution, RadosFuture, RadosFinishWrite};
use errors::Result;
use rados::RadosContext;

struct WriteState {
    caution: RadosCaution,
    futures: Vec<RadosFuture<RadosFinishWrite>>,
}

impl WriteState {
    /// Asynchronously write to the RADOS cluster, and push the resulting
    /// future into a `Vec` so that all unresolved futures can be `.wait()`d
    /// later.
    fn do_write(&mut self,
                ctx: &RadosContext,
                obj: &CStr,
                buf: &[u8],
                offset: &mut u64)
                -> Result<usize> {
        let future = ctx.write_async(self.caution, obj, buf, *offset)?;
        self.futures.push(future);
        *offset += buf.len() as u64;
        Ok(buf.len())
    }

    /// Call `.wait()` on every saved future.
    fn do_flush(&mut self) -> Result<()> {
        for (i, future) in self.futures.drain(..).enumerate() {
            println!("Waiting on future number {}...", i);
            future.wait()?;
        }
        println!("All futures resolved.");

        Ok(())
    }
}

/// A `Read`/`Write`/`Seek` interface to a RADOS object.
///
/// `RadosObject` will perform asynchronous I/O calls on `Write`, and
/// synchronous calls on `Read`. If calling `Seek::seek` with
/// `SeekFrom::End`, a synchronous call to `rados_stat` will be made;
/// otherwise, seeking is very cheap and completely local.
pub struct RadosObject {
    ctx: RadosContext,
    obj: CString,
    offset: u64,
    write_state: WriteState,
}

impl RadosObject {
    pub fn new(ctx: RadosContext, caution: RadosCaution, obj: CString) -> RadosObject {
        RadosObject {
            ctx,
            obj,
            offset: 0,
            write_state: WriteState {
                caution,
                futures: Vec::new(),
            },
        }
    }

    /// Calling `finish` will *not* cause asynchronous writes to be
    /// flushed. To block on write completion, use `Write::flush`.
    pub fn finish(self) -> RadosContext {
        self.ctx
    }
}

impl Read for RadosObject {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.ctx
            .read(self.obj.as_ref(), buf, self.offset)
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;

        self.offset += res as u64;
        Ok(res)
    }
}

impl Write for RadosObject {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.write_state
            .do_write(&self.ctx, self.obj.as_ref(), buf, &mut self.offset)
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.write_state
            .do_flush()
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))
    }
}

impl Seek for RadosObject {
    fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
        match from {
            SeekFrom::Start(u) => self.offset = u,
            SeekFrom::End(i) => {
                let length = self.ctx
                    .stat(self.obj.as_ref())
                    .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?
                    .size;

                self.offset = if i < 0 {
                    length - (-i as u64)
                } else {
                    length + (i as u64)
                };
            }
            SeekFrom::Current(i) => {
                if i < 0 {
                    self.offset -= -i as u64;
                } else {
                    self.offset += i as u64;
                }
            }
        }

        Ok(self.offset)
    }
}
<commit_msg>Fix #1<commit_after>//! Wrappers implementing `Read`, `Write`, and `Seek` for doing I/O on individual
//! RADOS objects.

use std::ffi::{CStr, CString};
use std::io::{self, SeekFrom, Read, Seek, Write};

use futures::future::{ok, Future};
use futures::stream::{FuturesUnordered, Stream};

use async::{RadosCaution, RadosFuture, RadosFinishWrite};
use errors::Result;
use rados::RadosContext;

struct WriteState {
    caution: RadosCaution,
    futures: FuturesUnordered<RadosFuture<RadosFinishWrite>>,
}

impl WriteState {
    /// Asynchronously write to the RADOS cluster, and push the resulting
    /// future into a `Vec` so that all unresolved futures can be `.wait()`d
    /// later.
    fn do_write(
        &mut self,
        ctx: &RadosContext,
        obj: &CStr,
        buf: &[u8],
        offset: &mut u64,
    ) -> Result<usize> {
        let future = ctx.write_async(self.caution, obj, buf, *offset)?;
        self.futures.push(future);
        *offset += buf.len() as u64;

        Ok(buf.len())
    }

    /// Call `.wait()` on every saved future.
    fn do_flush(&mut self) -> Result<()> {
        self.futures.by_ref().for_each(ok).wait()?;

        Ok(())
    }
}

/// A `Read`/`Write`/`Seek` interface to a RADOS object.
///
/// `RadosObject` will perform asynchronous I/O calls on `Write`, and
/// synchronous calls on `Read`. If calling `Seek::seek` with
/// `SeekFrom::End`, a synchronous call to `rados_stat` will be made;
/// otherwise, seeking is very cheap and completely local.
pub struct RadosObject {
    ctx: RadosContext,
    obj: CString,
    offset: u64,
    write_state: WriteState,
}

impl RadosObject {
    pub fn new(ctx: RadosContext, caution: RadosCaution, obj: CString) -> RadosObject {
        RadosObject {
            ctx,
            obj,
            offset: 0,
            write_state: WriteState {
                caution,
                futures: FuturesUnordered::new(),
            },
        }
    }

    /// Calling `finish` will *not* cause asynchronous writes to be
    /// flushed. To block on write completion, use `Write::flush`.
    pub fn finish(self) -> RadosContext {
        self.ctx
    }
}

impl Read for RadosObject {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.ctx.read(self.obj.as_ref(), buf, self.offset).map_err(
            |err| {
                io::Error::new(io::ErrorKind::Other, err.to_string())
            },
        )?;

        self.offset += res as u64;
        Ok(res)
    }
}

impl Write for RadosObject {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.write_state
            .do_write(&self.ctx, self.obj.as_ref(), buf, &mut self.offset)
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.write_state.do_flush().map_err(|err| {
            io::Error::new(io::ErrorKind::Other, err.to_string())
        })
    }
}

impl Seek for RadosObject {
    fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
        match from {
            SeekFrom::Start(u) => self.offset = u,
            SeekFrom::End(i) => {
                let length = self.ctx
                    .stat(self.obj.as_ref())
                    .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?
                    .size;

                self.offset = if i < 0 {
                    length - (-i as u64)
                } else {
                    length + (i as u64)
                };
            }
            SeekFrom::Current(i) => {
                if i < 0 {
                    self.offset -= -i as u64;
                } else {
                    self.offset += i as u64;
                }
            }
        }

        Ok(self.offset)
    }
}
<|endoftext|>


<commit_before>use euclid::{Vector2D, vec2};
use hex::Dir6;
use num::Integer;

/// User data for field of view cells.
pub trait FovValue: PartialEq + Clone {
    /// Construct a new FovValue for a position based on the previous one along the line of sight.
    fn advance(&self, offset: Vector2D<i32>) -> Option<Self>;

    /// Return whether the given offset contains an isometric wall tile.
    ///
    /// Optional method for showing acute corners of fake isometric rooms in fov.
    fn is_fake_isometric_wall(&self, offset: Vector2D<i32>) -> bool {
        let _ = offset;
        false
    }
}

/// Field of view iterator for a hexagonal map.
pub struct HexFov<T> {
    stack: Vec<Arc<T>>,
    /// Extra values generated by special cases.
    side_channel: Vec<(Vector2D<i32>, T)>,
}

impl<T: FovValue> HexFov<T> {
    /// Create a new field of view iterator with a seed userdata for the origin position.
    pub fn new(init: T) -> HexFov<T> {
        // We could run f for (0, 0) here, but the traditional way for the FOV to work is to only
        // consider your surroundings, not the origin site itself.
        HexFov {
            stack: vec![
                Arc::new(
                    PolarPoint::new(0.0, 1),
                    PolarPoint::new(6.0, 1),
                    init.clone()
                ),
            ],
            // The FOV algorithm will not generate the origin point, so we use
            // the side channel to explicitly add it in the beginning.
            side_channel: vec![(vec2(0, 0), init)],
        }
    }

    /// Add visible horizontal corners to fake-isometric rooms.
    fn make_corners_visible(&mut self, current: &Arc<T>) {
        // We're moving along a vertical line on the hex circle, so there are side
        // points to check.
        if let Some(side_pos) = current.pt.side_point() {
            let next = current.pt.next();
            let next_value = current.prev_value.advance(next.to_v2());
            // If the next cell is within the current span and the current cell is
            // wallform, and current and next are in the same value group,
            if next.is_below(current.end) &&
                current.prev_value.is_fake_isometric_wall(
                    current.pt.to_v2(),
                ) && next_value == current.prev_value.advance(current.pt.to_v2())
            {
                if let Some(next_value) = next_value {
                    // and if both the next cell and the third corner point cell are
                    // wallforms, and the side point would not be otherwise
                    // visible:
                    if next_value.is_fake_isometric_wall(next.to_v2()) &&
                        next_value.advance(side_pos).is_none() &&
                        next_value.is_fake_isometric_wall(side_pos)
                    {
                        // Add the side point to the side channel.
                        self.side_channel.push(
                            (side_pos, current.prev_value.clone()),
                        );
                    }
                }
            }
        }
    }
}

impl<T: FovValue> Iterator for HexFov<T> {
    type Item = (Vector2D<i32>, T);
    fn next(&mut self) -> Option<(Vector2D<i32>, T)> {
        // Empty the side channel before proceeding to the algorithm proper.
        if let Some(ret) = self.side_channel.pop() {
            return Some(ret);
        }

        // Start processing the next arc in the stack.
        if let Some(current) = self.stack.pop() {
            if current.arc_has_split(&mut self.stack) {
                return self.next();
            }

            debug_assert!(current.group_value == current.prev_value.advance(current.pt.to_v2()));

            self.make_corners_visible(&current);

            let pos = current.pt.to_v2();
            let ret = current.group_value.clone();

            current.advance(&mut self.stack);

            if let Some(ret) = ret {
                return Some((pos, ret));
            } else {
                return self.next();
            }
        } else {
            None
        }
    }
}

struct Arc<T> {
    /// Start point of current arc.
    begin: PolarPoint,
    /// Point currently being processed.
    pt: PolarPoint,
    /// End point of current arc.
    end: PolarPoint,
    /// The user value from previous iteration.
    prev_value: T,
    /// The user value for this group.
    group_value: Option<T>,
}

impl<T: FovValue> Arc<T> {
    pub fn new(begin: PolarPoint, end: PolarPoint, prev_value: T) -> Arc<T> {
        let group_value = prev_value.advance(begin.to_v2());
        Arc {
            begin: begin,
            pt: begin,
            end: end,
            prev_value: prev_value,
            group_value: group_value,
        }
    }

    /// Consume the given arc and add its descendent, if any, to the stack.
    pub fn advance(mut self, stack: &mut Vec<Arc<T>>) {
        self.pt = self.pt.next();
        if self.pt.is_below(self.end) {
            stack.push(self);
        } else if let Some(group_value) = self.group_value {
            stack.push(Arc::new(
                self.begin.further(),
                self.end.further(),
                group_value,
            ));
        }
    }

    /// If the arc has advanced into a different value group, split it into the given stack.
    ///
    /// Return true if arc was split, false otherwise.
    pub fn arc_has_split(&self, stack: &mut Vec<Arc<T>>) -> bool {
        let next_value = self.prev_value.advance(self.pt.to_v2());
        if next_value != self.group_value {
            // Using the literal instead of the constructor to avoid recomputing next_value.
            stack.push(Arc {
                begin: self.pt,
                pt: self.pt,
                end: self.end,
                prev_value: self.prev_value.clone(),
                group_value: next_value,
            });

            // Extend current arc if it has a group value.
            if let Some(ref group_value) = self.group_value {
                stack.push(Arc::new(
                    self.begin.further(),
                    self.pt.further(),
                    group_value.clone(),
                ));
            }

            true
        } else {
            false
        }
    }
}

/// Points on a hex circle expressed in polar coordinates.
#[derive(Copy, Clone, PartialEq)]
struct PolarPoint {
    pos: f32,
    radius: u32,
}

impl PolarPoint {
    pub fn new(pos: f32, radius: u32) -> PolarPoint { PolarPoint { pos, radius } }

    /// Index of the discrete hex cell along the circle that corresponds to this point.
    fn winding_index(self) -> i32 { (self.pos + 0.5).floor() as i32 }

    pub fn is_below(self, other: PolarPoint) -> bool { self.winding_index() < other.end_index() }

    fn end_index(self) -> i32 { (self.pos + 0.5).ceil() as i32 }

    pub fn to_v2(self) -> Vector2D<i32> {
        if self.radius == 0 {
            return vec2(0, 0);
        }
        let index = self.winding_index();
        let sector = index.mod_floor(&(self.radius as i32 * 6)) / self.radius as i32;
        let offset = index.mod_floor(&(self.radius as i32));

        let rod = Dir6::from_int(sector).to_v2();
        let tangent = Dir6::from_int((sector + 2) % 6).to_v2();

        rod * (self.radius as i32) + tangent * offset
    }

    /// If this point and the next point are adjacent vertically (along the xy
    /// axis), return the point outside of the circle between the two points.
    ///
    /// This is a helper function for the FOV special case where acute corners
    /// of fake isometric rooms are marked visible even though strict hex FOV
    /// logic would keep them unseen.
    pub fn side_point(self) -> Option<Vector2D<i32>> {
        let next = self.next();
        let a = self.to_v2();
        let b = next.to_v2();

        if b.x == a.x + 1 && b.y == a.y + 1 {
            // Going down the right rim.
            Some(vec2(a.x + 1, a.y))
        } else if b.x == a.x - 1 && b.y == a.y - 1 {
            // Going up the left rim.
            Some(vec2(a.x - 1, a.y))
        } else {
            None
        }
    }

    /// The point corresponding to this one on the hex circle with radius +1.
    pub fn further(self) -> PolarPoint {
        PolarPoint::new(
            self.pos * (self.radius + 1) as f32 / self.radius as f32,
            self.radius + 1,
        )
    }

    /// The point next to this one along the hex circle.
    pub fn next(self) -> PolarPoint { PolarPoint::new((self.pos + 0.5).floor() + 0.5, self.radius) }
}

#[cfg(test)]
mod test {
    use super::{FovValue, HexFov};
    use euclid::{Vector2D, vec2};
    use hex::HexGeom;
    use std::collections::HashMap;
    use std::iter::FromIterator;

    #[derive(PartialEq, Eq, Clone)]
    struct Cell1 {
        range: i32,
    }

    impl FovValue for Cell1 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }
    }

    #[derive(PartialEq, Eq, Clone)]
    struct Cell2 {
        range: i32,
    }

    impl FovValue for Cell2 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }

        fn is_fake_isometric_wall(&self, offset: Vector2D<i32>) -> bool {
            let _ = offset;
            true
        }
    }

    #[test]
    fn trivial_fov() {
        // Just draw a small circle.
        let field: HashMap<Vector2D<i32>, Cell1> =
            HashMap::from_iter(HexFov::new(Cell1 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(!field.contains_key(&vec2(1, -1)));

        // Now test out the fake-isometric corners.
        let field: HashMap<Vector2D<i32>, Cell2> =
            HashMap::from_iter(HexFov::new(Cell2 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(field.contains_key(&vec2(1, -1)));
    }
}
<commit_msg>Modulo is handled by Dir6::from_int<commit_after>use euclid::{Vector2D, vec2};
use hex::Dir6;
use num::Integer;

/// User data for field of view cells.
pub trait FovValue: PartialEq + Clone {
    /// Construct a new FovValue for a position based on the previous one along the line of sight.
    fn advance(&self, offset: Vector2D<i32>) -> Option<Self>;

    /// Return whether the given offset contains an isometric wall tile.
    ///
    /// Optional method for showing acute corners of fake isometric rooms in fov.
    fn is_fake_isometric_wall(&self, offset: Vector2D<i32>) -> bool {
        let _ = offset;
        false
    }
}

/// Field of view iterator for a hexagonal map.
pub struct HexFov<T> {
    stack: Vec<Arc<T>>,
    /// Extra values generated by special cases.
    side_channel: Vec<(Vector2D<i32>, T)>,
}

impl<T: FovValue> HexFov<T> {
    /// Create a new field of view iterator with a seed userdata for the origin position.
    pub fn new(init: T) -> HexFov<T> {
        // We could run f for (0, 0) here, but the traditional way for the FOV to work is to only
        // consider your surroundings, not the origin site itself.
        HexFov {
            stack: vec![
                Arc::new(
                    PolarPoint::new(0.0, 1),
                    PolarPoint::new(6.0, 1),
                    init.clone()
                ),
            ],
            // The FOV algorithm will not generate the origin point, so we use
            // the side channel to explicitly add it in the beginning.
            side_channel: vec![(vec2(0, 0), init)],
        }
    }

    /// Add visible horizontal corners to fake-isometric rooms.
    fn make_corners_visible(&mut self, current: &Arc<T>) {
        // We're moving along a vertical line on the hex circle, so there are side
        // points to check.
        if let Some(side_pos) = current.pt.side_point() {
            let next = current.pt.next();
            let next_value = current.prev_value.advance(next.to_v2());
            // If the next cell is within the current span and the current cell is
            // wallform, and current and next are in the same value group,
            if next.is_below(current.end) &&
                current.prev_value.is_fake_isometric_wall(
                    current.pt.to_v2(),
                ) && next_value == current.prev_value.advance(current.pt.to_v2())
            {
                if let Some(next_value) = next_value {
                    // and if both the next cell and the third corner point cell are
                    // wallforms, and the side point would not be otherwise
                    // visible:
                    if next_value.is_fake_isometric_wall(next.to_v2()) &&
                        next_value.advance(side_pos).is_none() &&
                        next_value.is_fake_isometric_wall(side_pos)
                    {
                        // Add the side point to the side channel.
                        self.side_channel.push(
                            (side_pos, current.prev_value.clone()),
                        );
                    }
                }
            }
        }
    }
}

impl<T: FovValue> Iterator for HexFov<T> {
    type Item = (Vector2D<i32>, T);
    fn next(&mut self) -> Option<(Vector2D<i32>, T)> {
        // Empty the side channel before proceeding to the algorithm proper.
        if let Some(ret) = self.side_channel.pop() {
            return Some(ret);
        }

        // Start processing the next arc in the stack.
        if let Some(current) = self.stack.pop() {
            if current.arc_has_split(&mut self.stack) {
                return self.next();
            }

            debug_assert!(current.group_value == current.prev_value.advance(current.pt.to_v2()));

            self.make_corners_visible(&current);

            let pos = current.pt.to_v2();
            let ret = current.group_value.clone();

            current.advance(&mut self.stack);

            if let Some(ret) = ret {
                return Some((pos, ret));
            } else {
                return self.next();
            }
        } else {
            None
        }
    }
}

struct Arc<T> {
    /// Start point of current arc.
    begin: PolarPoint,
    /// Point currently being processed.
    pt: PolarPoint,
    /// End point of current arc.
    end: PolarPoint,
    /// The user value from previous iteration.
    prev_value: T,
    /// The user value for this group.
    group_value: Option<T>,
}

impl<T: FovValue> Arc<T> {
    pub fn new(begin: PolarPoint, end: PolarPoint, prev_value: T) -> Arc<T> {
        let group_value = prev_value.advance(begin.to_v2());
        Arc {
            begin: begin,
            pt: begin,
            end: end,
            prev_value: prev_value,
            group_value: group_value,
        }
    }

    /// Consume the given arc and add its descendent, if any, to the stack.
    pub fn advance(mut self, stack: &mut Vec<Arc<T>>) {
        self.pt = self.pt.next();
        if self.pt.is_below(self.end) {
            stack.push(self);
        } else if let Some(group_value) = self.group_value {
            stack.push(Arc::new(
                self.begin.further(),
                self.end.further(),
                group_value,
            ));
        }
    }

    /// If the arc has advanced into a different value group, split it into the given stack.
    ///
    /// Return true if arc was split, false otherwise.
    pub fn arc_has_split(&self, stack: &mut Vec<Arc<T>>) -> bool {
        let next_value = self.prev_value.advance(self.pt.to_v2());
        if next_value != self.group_value {
            // Using the literal instead of the constructor to avoid recomputing next_value.
            stack.push(Arc {
                begin: self.pt,
                pt: self.pt,
                end: self.end,
                prev_value: self.prev_value.clone(),
                group_value: next_value,
            });

            // Extend current arc if it has a group value.
            if let Some(ref group_value) = self.group_value {
                stack.push(Arc::new(
                    self.begin.further(),
                    self.pt.further(),
                    group_value.clone(),
                ));
            }

            true
        } else {
            false
        }
    }
}

/// Points on a hex circle expressed in polar coordinates.
#[derive(Copy, Clone, PartialEq)]
struct PolarPoint {
    pos: f32,
    radius: u32,
}

impl PolarPoint {
    pub fn new(pos: f32, radius: u32) -> PolarPoint { PolarPoint { pos, radius } }

    /// Index of the discrete hex cell along the circle that corresponds to this point.
    fn winding_index(self) -> i32 { (self.pos + 0.5).floor() as i32 }

    pub fn is_below(self, other: PolarPoint) -> bool { self.winding_index() < other.end_index() }

    fn end_index(self) -> i32 { (self.pos + 0.5).ceil() as i32 }

    pub fn to_v2(self) -> Vector2D<i32> {
        if self.radius == 0 {
            return vec2(0, 0);
        }
        let index = self.winding_index();
        let sector = index.mod_floor(&(self.radius as i32 * 6)) / self.radius as i32;
        let offset = index.mod_floor(&(self.radius as i32));

        let rod = Dir6::from_int(sector).to_v2();
        let tangent = Dir6::from_int(sector + 2).to_v2();

        rod * (self.radius as i32) + tangent * offset
    }

    /// If this point and the next point are adjacent vertically (along the xy
    /// axis), return the point outside of the circle between the two points.
    ///
    /// This is a helper function for the FOV special case where acute corners
    /// of fake isometric rooms are marked visible even though strict hex FOV
    /// logic would keep them unseen.
    pub fn side_point(self) -> Option<Vector2D<i32>> {
        let next = self.next();
        let a = self.to_v2();
        let b = next.to_v2();

        if b.x == a.x + 1 && b.y == a.y + 1 {
            // Going down the right rim.
            Some(vec2(a.x + 1, a.y))
        } else if b.x == a.x - 1 && b.y == a.y - 1 {
            // Going up the left rim.
            Some(vec2(a.x - 1, a.y))
        } else {
            None
        }
    }

    /// The point corresponding to this one on the hex circle with radius +1.
    pub fn further(self) -> PolarPoint {
        PolarPoint::new(
            self.pos * (self.radius + 1) as f32 / self.radius as f32,
            self.radius + 1,
        )
    }

    /// The point next to this one along the hex circle.
    pub fn next(self) -> PolarPoint { PolarPoint::new((self.pos + 0.5).floor() + 0.5, self.radius) }
}

#[cfg(test)]
mod test {
    use super::{FovValue, HexFov};
    use euclid::{Vector2D, vec2};
    use hex::HexGeom;
    use std::collections::HashMap;
    use std::iter::FromIterator;

    #[derive(PartialEq, Eq, Clone)]
    struct Cell1 {
        range: i32,
    }

    impl FovValue for Cell1 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }
    }

    #[derive(PartialEq, Eq, Clone)]
    struct Cell2 {
        range: i32,
    }

    impl FovValue for Cell2 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }

        fn is_fake_isometric_wall(&self, offset: Vector2D<i32>) -> bool {
            let _ = offset;
            true
        }
    }

    #[test]
    fn trivial_fov() {
        // Just draw a small circle.
        let field: HashMap<Vector2D<i32>, Cell1> =
            HashMap::from_iter(HexFov::new(Cell1 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(!field.contains_key(&vec2(1, -1)));

        // Now test out the fake-isometric corners.
        let field: HashMap<Vector2D<i32>, Cell2> =
            HashMap::from_iter(HexFov::new(Cell2 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(field.contains_key(&vec2(1, -1)));
    }
}
<|endoftext|>


<commit_before>//! Defines the `IntoIter` owned iterator for arrays.

use crate::{
    fmt,
    iter::{ExactSizeIterator, FusedIterator, TrustedLen},
    mem::{self, MaybeUninit},
    ops::Range,
    ptr,
};

/// A by-value [array] iterator.
///
/// [array]: ../../std/primitive.array.html
#[unstable(feature = "array_value_iter", issue = "65798")]
pub struct IntoIter<T, const N: usize> {
    /// This is the array we are iterating over.
    ///
    /// Elements with index `i` where `alive.start <= i < alive.end` have not
    /// been yielded yet and are valid array entries. Elements with indices `i
    /// < alive.start` or `i >= alive.end` have been yielded already and must
    /// not be accessed anymore! Those dead elements might even be in a
    /// completely uninitialized state!
    ///
    /// So the invariants are:
    /// - `data[alive]` is alive (i.e. contains valid elements)
    /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
    ///   elements were already read and must not be touched anymore!)
    data: [MaybeUninit<T>; N],

    /// The elements in `data` that have not been yielded yet.
    ///
    /// Invariants:
    /// - `alive.start <= alive.end`
    /// - `alive.end <= N`
    alive: Range<usize>,
}

impl<T, const N: usize> IntoIter<T, N> {
    /// Creates a new iterator over the given `array`.
    ///
    /// *Note*: this method might never get stabilized and/or removed in the
    /// future as there will likely be another, preferred way of obtaining this
    /// iterator (either via `IntoIterator` for arrays or via another way).
    #[unstable(feature = "array_value_iter", issue = "65798")]
    pub fn new(array: [T; N]) -> Self {
        // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
        // promise:
        //
        // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
        // > as `T`.
        //
        // The docs even show a transmute from an array of `MaybeUninit<T>` to
        // an array of `T`.
        //
        // With that, this initialization satisfies the invariants.

        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
        // works with const generics:
        //     `mem::transmute::<[T; {N}], [MaybeUninit<T>; {N}]>(array)`
        //
        // Until then, we do it manually here. We first create a bitwise copy
        // but cast the pointer so that it is treated as a different type. Then
        // we forget `array` so that it is not dropped.
        let data = unsafe {
            let data = ptr::read(&array as *const [T; N] as *const [MaybeUninit<T>; N]);
            mem::forget(array);
            data
        };

        Self { data, alive: 0..N }
    }

    /// Returns an immutable slice of all elements that have not been yielded
    /// yet.
    fn as_slice(&self) -> &[T] {
        let slice = &self.data[self.alive.clone()];
        // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains
        // the size and alignment of `T`. Furthermore, we know that all
        // elements within `alive` are properly initialized.
        unsafe { mem::transmute::<&[MaybeUninit<T>], &[T]>(slice) }
    }

    /// Returns a mutable slice of all elements that have not been yielded yet.
    fn as_mut_slice(&mut self) -> &mut [T] {
        // This transmute is safe, same as in `as_slice` above.
        let slice = &mut self.data[self.alive.clone()];
        // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains
        // the size and alignment of `T`. Furthermore, we know that all
        // elements within `alive` are properly initialized.
        unsafe { mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(slice) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Iterator for IntoIter<T, N> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        if self.alive.start == self.alive.end {
            return None;
        }

        // Bump start index.
        //
        // From the check above we know that `alive.start != alive.end`.
        // Combine this with the invariant `alive.start <= alive.end`, we know
        // that `alive.start < alive.end`. Increasing `alive.start` by 1
        // maintains the invariant regarding `alive`. However, due to this
        // change, for a short time, the alive zone is not `data[alive]`
        // anymore, but `data[idx..alive.end]`.
        let idx = self.alive.start;
        self.alive.start += 1;

        // Read the element from the array.
        // SAFETY: This is safe: `idx` is an index
        // into the "alive" region of the array. Reading this element means
        // that `data[idx]` is regarded as dead now (i.e. do not touch). As
        // `idx` was the start of the alive-zone, the alive zone is now
        // `data[alive]` again, restoring all invariants.
        let out = unsafe { self.data.get_unchecked(idx).read() };

        Some(out)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    fn count(self) -> usize {
        self.len()
    }

    fn last(mut self) -> Option<Self::Item> {
        self.next_back()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.alive.start == self.alive.end {
            return None;
        }

        // Decrease end index.
        //
        // From the check above we know that `alive.start != alive.end`.
        // Combine this with the invariant `alive.start <= alive.end`, we know
        // that `alive.start < alive.end`. As `alive.start` cannot be negative,
        // `alive.end` is at least 1, meaning that we can safely decrement it
        // by one. This also maintains the invariant `alive.start <=
        // alive.end`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[alive.start..alive.end
        // + 1]`.
        self.alive.end -= 1;

        // Read the element from the array.
        // SAFETY: This is safe: `alive.end` is an
        // index into the "alive" region of the array. Compare the previous
        // comment that states that the alive region is
        // `data[alive.start..alive.end + 1]`. Reading this element means that
        // `data[alive.end]` is regarded as dead now (i.e. do not touch). As
        // `alive.end` was the end of the alive-zone, the alive zone is now
        // `data[alive]` again, restoring all invariants.
        let out = unsafe { self.data.get_unchecked(self.alive.end).read() };

        Some(out)
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Drop for IntoIter<T, N> {
    fn drop(&mut self) {
        // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
        // of elements that have not been moved out yet and that remain
        // to be dropped.
        unsafe { ptr::drop_in_place(self.as_mut_slice()) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
    fn len(&self) -> usize {
        // Will never underflow due to the invariant `alive.start <=
        // alive.end`.
        self.alive.end - self.alive.start
    }
    fn is_empty(&self) -> bool {
        self.alive.is_empty()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
    fn clone(&self) -> Self {
        // SAFETY: each point of unsafety is documented inside the unsafe block
        unsafe {
            // This creates a new uninitialized array. Note that the `assume_init`
            // refers to the array, not the individual elements. And it is Ok if
            // the array is in an uninitialized state as all elements may be
            // uninitialized (all bit patterns are valid). Compare the
            // `MaybeUninit` docs for more information.
            let mut new_data: [MaybeUninit<T>; N] = MaybeUninit::uninit().assume_init();

            // Clone all alive elements.
            for idx in self.alive.clone() {
                // The element at `idx` in the old array is alive, so we can
                // safely call `get_ref()`. We then clone it, and write the
                // clone into the new array.
                let clone = self.data.get_unchecked(idx).get_ref().clone();
                new_data.get_unchecked_mut(idx).write(clone);
            }

            Self { data: new_data, alive: self.alive.clone() }
        }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Only print the elements that were not yielded yet: we cannot
        // access the yielded elements anymore.
        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
    }
}
<commit_msg>Simplify array::IntoIter<commit_after>//! Defines the `IntoIter` owned iterator for arrays.

use crate::{
    fmt,
    iter::{ExactSizeIterator, FusedIterator, TrustedLen},
    mem::{self, MaybeUninit},
    ops::Range,
    ptr,
};

/// A by-value [array] iterator.
///
/// [array]: ../../std/primitive.array.html
#[unstable(feature = "array_value_iter", issue = "65798")]
pub struct IntoIter<T, const N: usize> {
    /// This is the array we are iterating over.
    ///
    /// Elements with index `i` where `alive.start <= i < alive.end` have not
    /// been yielded yet and are valid array entries. Elements with indices `i
    /// < alive.start` or `i >= alive.end` have been yielded already and must
    /// not be accessed anymore! Those dead elements might even be in a
    /// completely uninitialized state!
    ///
    /// So the invariants are:
    /// - `data[alive]` is alive (i.e. contains valid elements)
    /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
    ///   elements were already read and must not be touched anymore!)
    data: [MaybeUninit<T>; N],

    /// The elements in `data` that have not been yielded yet.
    ///
    /// Invariants:
    /// - `alive.start <= alive.end`
    /// - `alive.end <= N`
    alive: Range<usize>,
}

impl<T, const N: usize> IntoIter<T, N> {
    /// Creates a new iterator over the given `array`.
    ///
    /// *Note*: this method might never get stabilized and/or removed in the
    /// future as there will likely be another, preferred way of obtaining this
    /// iterator (either via `IntoIterator` for arrays or via another way).
    #[unstable(feature = "array_value_iter", issue = "65798")]
    pub fn new(array: [T; N]) -> Self {
        // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
        // promise:
        //
        // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
        // > as `T`.
        //
        // The docs even show a transmute from an array of `MaybeUninit<T>` to
        // an array of `T`.
        //
        // With that, this initialization satisfies the invariants.

        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
        // works with const generics:
        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
        //
        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
        // as a different type, then forget `array` so that it is not dropped.
        unsafe {
            let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
            mem::forget(array);
            iter
        }
    }

    /// Returns an immutable slice of all elements that have not been yielded
    /// yet.
    fn as_slice(&self) -> &[T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked(self.alive.clone());
            MaybeUninit::slice_get_ref(slice)
        }
    }

    /// Returns a mutable slice of all elements that have not been yielded yet.
    fn as_mut_slice(&mut self) -> &mut [T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked_mut(self.alive.clone());
            MaybeUninit::slice_get_mut(slice)
        }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Iterator for IntoIter<T, N> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // Get the next index from the front.
        //
        // Increasing `alive.start` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
        self.alive.next().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the start of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).read() }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    fn count(self) -> usize {
        self.len()
    }

    fn last(mut self) -> Option<Self::Item> {
        self.next_back()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        // Get the next index from the back.
        //
        // Decreasing `alive.end` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
        self.alive.next_back().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the end of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).read() }
        })
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Drop for IntoIter<T, N> {
    fn drop(&mut self) {
        // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
        // of elements that have not been moved out yet and that remain
        // to be dropped.
        unsafe { ptr::drop_in_place(self.as_mut_slice()) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
    fn len(&self) -> usize {
        // Will never underflow due to the invariant `alive.start <=
        // alive.end`.
        self.alive.end - self.alive.start
    }
    fn is_empty(&self) -> bool {
        self.alive.is_empty()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
    fn clone(&self) -> Self {
        // Note, we don't really need to match the exact same alive range, so
        // we can just clone into offset 0 regardless of where `self` is.
        let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };

        // Clone all alive elements.
        for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
            // Write a clone into the new array, then update its alive range.
            // If cloning panics, we'll correctly drop the previous items.
            dst.write(src.clone());
            new.alive.end += 1;
        }

        new
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Only print the elements that were not yielded yet: we cannot
        // access the yielded elements anymore.
        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
    }
}
<|endoftext|>


<commit_before>//! Defines the `IntoIter` owned iterator for arrays.

use crate::{
    fmt,
    iter::{ExactSizeIterator, FusedIterator, TrustedLen},
    mem::{self, MaybeUninit},
    ops::Range,
    ptr,
};

/// A by-value [array] iterator.
///
/// [array]: ../../std/primitive.array.html
#[stable(feature = "array_value_iter", since = "1.51.0")]
pub struct IntoIter<T, const N: usize> {
    /// This is the array we are iterating over.
    ///
    /// Elements with index `i` where `alive.start <= i < alive.end` have not
    /// been yielded yet and are valid array entries. Elements with indices `i
    /// < alive.start` or `i >= alive.end` have been yielded already and must
    /// not be accessed anymore! Those dead elements might even be in a
    /// completely uninitialized state!
    ///
    /// So the invariants are:
    /// - `data[alive]` is alive (i.e. contains valid elements)
    /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
    ///   elements were already read and must not be touched anymore!)
    data: [MaybeUninit<T>; N],

    /// The elements in `data` that have not been yielded yet.
    ///
    /// Invariants:
    /// - `alive.start <= alive.end`
    /// - `alive.end <= N`
    alive: Range<usize>,
}

impl<T, const N: usize> IntoIter<T, N> {
    /// Creates a new iterator over the given `array`.
    ///
    /// *Note*: this method might be deprecated in the future,
    /// after [`IntoIterator` is implemented for arrays][array-into-iter].
    ///
    /// [array-into-iter]: https://github.com/rust-lang/rust/pull/65819
    #[stable(feature = "array_value_iter", since = "1.51.0")]
    pub fn new(array: [T; N]) -> Self {
        // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
        // promise:
        //
        // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
        // > as `T`.
        //
        // The docs even show a transmute from an array of `MaybeUninit<T>` to
        // an array of `T`.
        //
        // With that, this initialization satisfies the invariants.

        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
        // works with const generics:
        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
        //
        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
        // as a different type, then forget `array` so that it is not dropped.
        unsafe {
            let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
            mem::forget(array);
            iter
        }
    }

    /// Returns an immutable slice of all elements that have not been yielded
    /// yet.
    #[stable(feature = "array_value_iter", since = "1.51.0")]
    pub fn as_slice(&self) -> &[T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked(self.alive.clone());
            MaybeUninit::slice_assume_init_ref(slice)
        }
    }

    /// Returns a mutable slice of all elements that have not been yielded yet.
    #[stable(feature = "array_value_iter", since = "1.51.0")]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked_mut(self.alive.clone());
            MaybeUninit::slice_assume_init_mut(slice)
        }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Iterator for IntoIter<T, N> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // Get the next index from the front.
        //
        // Increasing `alive.start` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
        self.alive.next().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the start of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    fn count(self) -> usize {
        self.len()
    }

    fn last(mut self) -> Option<Self::Item> {
        self.next_back()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        // Get the next index from the back.
        //
        // Decreasing `alive.end` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
        self.alive.next_back().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the end of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Drop for IntoIter<T, N> {
    fn drop(&mut self) {
        // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
        // of elements that have not been moved out yet and that remain
        // to be dropped.
        unsafe { ptr::drop_in_place(self.as_mut_slice()) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
    fn len(&self) -> usize {
        // Will never underflow due to the invariant `alive.start <=
        // alive.end`.
        self.alive.end - self.alive.start
    }
    fn is_empty(&self) -> bool {
        self.alive.is_empty()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
    fn clone(&self) -> Self {
        // Note, we don't really need to match the exact same alive range, so
        // we can just clone into offset 0 regardless of where `self` is.
        let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };

        // Clone all alive elements.
        for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
            // Write a clone into the new array, then update its alive range.
            // If cloning panics, we'll correctly drop the previous items.
            dst.write(src.clone());
            new.alive.end += 1;
        }

        new
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Only print the elements that were not yielded yet: we cannot
        // access the yielded elements anymore.
        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
    }
}
<commit_msg>Add example to array::IntoIter::new’s doc-comment<commit_after>//! Defines the `IntoIter` owned iterator for arrays.

use crate::{
    fmt,
    iter::{ExactSizeIterator, FusedIterator, TrustedLen},
    mem::{self, MaybeUninit},
    ops::Range,
    ptr,
};

/// A by-value [array] iterator.
///
/// [array]: ../../std/primitive.array.html
#[stable(feature = "array_value_iter", since = "1.51.0")]
pub struct IntoIter<T, const N: usize> {
    /// This is the array we are iterating over.
    ///
    /// Elements with index `i` where `alive.start <= i < alive.end` have not
    /// been yielded yet and are valid array entries. Elements with indices `i
    /// < alive.start` or `i >= alive.end` have been yielded already and must
    /// not be accessed anymore! Those dead elements might even be in a
    /// completely uninitialized state!
    ///
    /// So the invariants are:
    /// - `data[alive]` is alive (i.e. contains valid elements)
    /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
    ///   elements were already read and must not be touched anymore!)
    data: [MaybeUninit<T>; N],

    /// The elements in `data` that have not been yielded yet.
    ///
    /// Invariants:
    /// - `alive.start <= alive.end`
    /// - `alive.end <= N`
    alive: Range<usize>,
}

impl<T, const N: usize> IntoIter<T, N> {
    /// Creates a new iterator over the given `array`.
    ///
    /// *Note*: this method might be deprecated in the future,
    /// after [`IntoIterator` is implemented for arrays][array-into-iter].
    ///
    /// # Examples
    ///
    /// ```
    /// use std::array;
    ///
    /// for value in array::IntoIter::new([1, 2, 3, 4, 5]) {
    ///     // The type of `value` is a `i32` here, instead of `&i32`
    ///     let _: i32 = value;
    /// }
    /// ```
    /// [array-into-iter]: https://github.com/rust-lang/rust/pull/65819
    #[stable(feature = "array_value_iter", since = "1.51.0")]
    pub fn new(array: [T; N]) -> Self {
        // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
        // promise:
        //
        // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
        // > as `T`.
        //
        // The docs even show a transmute from an array of `MaybeUninit<T>` to
        // an array of `T`.
        //
        // With that, this initialization satisfies the invariants.

        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
        // works with const generics:
        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
        //
        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
        // as a different type, then forget `array` so that it is not dropped.
        unsafe {
            let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
            mem::forget(array);
            iter
        }
    }

    /// Returns an immutable slice of all elements that have not been yielded
    /// yet.
    #[stable(feature = "array_value_iter", since = "1.51.0")]
    pub fn as_slice(&self) -> &[T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked(self.alive.clone());
            MaybeUninit::slice_assume_init_ref(slice)
        }
    }

    /// Returns a mutable slice of all elements that have not been yielded yet.
    #[stable(feature = "array_value_iter", since = "1.51.0")]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked_mut(self.alive.clone());
            MaybeUninit::slice_assume_init_mut(slice)
        }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Iterator for IntoIter<T, N> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // Get the next index from the front.
        //
        // Increasing `alive.start` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
        self.alive.next().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the start of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    fn count(self) -> usize {
        self.len()
    }

    fn last(mut self) -> Option<Self::Item> {
        self.next_back()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        // Get the next index from the back.
        //
        // Decreasing `alive.end` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
        self.alive.next_back().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the end of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Drop for IntoIter<T, N> {
    fn drop(&mut self) {
        // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
        // of elements that have not been moved out yet and that remain
        // to be dropped.
        unsafe { ptr::drop_in_place(self.as_mut_slice()) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
    fn len(&self) -> usize {
        // Will never underflow due to the invariant `alive.start <=
        // alive.end`.
        self.alive.end - self.alive.start
    }
    fn is_empty(&self) -> bool {
        self.alive.is_empty()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
    fn clone(&self) -> Self {
        // Note, we don't really need to match the exact same alive range, so
        // we can just clone into offset 0 regardless of where `self` is.
        let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };

        // Clone all alive elements.
        for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
            // Write a clone into the new array, then update its alive range.
            // If cloning panics, we'll correctly drop the previous items.
            dst.write(src.clone());
            new.alive.end += 1;
        }

        new
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Only print the elements that were not yielded yet: we cannot
        // access the yielded elements anymore.
        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
extern crate retry;
#[macro_use]
extern crate log;
extern crate hyper;

use std::process::Command;
use std::error::Error;

/// This struct wraps a docker (for the moment explicitly ElasticSearch)
/// Allowing to setup a docker, tear it down and to provide its address and port
pub struct DockerWrapper {
    ip: String,
}

impl DockerWrapper {
    pub fn host(&self) -> String {
        format!("http://{}:9200", self.ip)
    }

    fn setup(&mut self) -> Result<(), Box<Error>> {
        info!("Launching ES docker");
        let status = try!(Command::new("docker")
            .args(&["run", "-d", "--name=mimirsbrunn_tests", "elasticsearch:2"])
            .status());
        if !status.success() {
            return Err(format!("`docker run` failed {}", &status).into());
        }

        // we need to get the ip of the container if the container has been run on another machine
        let container_ip_cmd = try!(Command::new("docker")
            .args(&["inspect", "--format={{.NetworkSettings.IPAddress}}", "mimirsbrunn_tests"])
            .output());

        let container_ip =
            std::str::from_utf8(container_ip_cmd.stdout.as_slice())?.replace("\n", "");

        warn!("container ip = {:?}", container_ip);
        self.ip = container_ip;

        info!("Waiting for ES in docker to be up and running...");
        match retry::retry(200,
                           100,
                           || hyper::client::Client::new().get(&self.host()).send(),
                           |response| {
                               response.as_ref()
                                   .map(|res| res.status == hyper::Ok)
                                   .unwrap_or(false)
                           }) {
            Ok(_) => Ok(()),
            Err(_) => Err("ES is down".into()),
        }
    }

    pub fn new() -> Result<DockerWrapper, Box<Error>> {
        let mut wrapper = DockerWrapper { ip: "".to_string() };
        try!(wrapper.setup());
        Ok(wrapper)
    }
}

fn docker_command(args: &[&'static str]) {
    info!("Running docker {:?}", args);
    let status = Command::new("docker").args(args).status();
    match status {
        Ok(s) => {
            if !s.success() {
                warn!("`docker {a:?}` failed {s}", a = args, s = s)
            }
        }
        Err(e) => warn!("command `docker {a:?}` failed {e}", a = args, e = e),
    }
}

impl Drop for DockerWrapper {
    fn drop(&mut self) {
        if std::env::var("DONT_KILL_THE_WHALE") == Ok("1".to_string()) {
            warn!("the docker won't be stoped at the end, you can debug it.
            Note: ES has been mapped to the port 9242 in you localhost
            manually stop and rm the container mimirsbrunn_tests after debug");
            return;
        }
        docker_command(&["stop", "mimirsbrunn_tests"]);
        docker_command(&["rm", "mimirsbrunn_tests"]);
    }
}
<commit_msg>corrections after review<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
extern crate retry;
#[macro_use]
extern crate log;
extern crate hyper;

use std::process::Command;
use std::error::Error;

/// This struct wraps a docker (for the moment explicitly ElasticSearch)
/// Allowing to setup a docker, tear it down and to provide its address and port
pub struct DockerWrapper {
    ip: String,
}

impl DockerWrapper {
    pub fn host(&self) -> String {
        format!("http://{}:9200", self.ip)
    }

    fn setup(&mut self) -> Result<(), Box<Error>> {
        info!("Launching ES docker");
        let status = try!(Command::new("docker")
            .args(&["run", "-d", "--name=mimirsbrunn_tests", "elasticsearch:2"])
            .status());
        if !status.success() {
            return Err(format!("`docker run` failed {}", &status).into());
        }

        // we need to get the ip of the container if the container has been run on another machine
        let container_ip_cmd = try!(Command::new("docker")
            .args(&["inspect", "--format={{.NetworkSettings.IPAddress}}", "mimirsbrunn_tests"])
            .output());

        let container_ip = std::str::from_utf8(container_ip_cmd.stdout.as_slice())?.trim();

        warn!("container ip = {:?}", container_ip);
        self.ip = container_ip.to_string();

        info!("Waiting for ES in docker to be up and running...");
        match retry::retry(200,
                           100,
                           || hyper::client::Client::new().get(&self.host()).send(),
                           |response| {
                               response.as_ref()
                                   .map(|res| res.status == hyper::Ok)
                                   .unwrap_or(false)
                           }) {
            Ok(_) => Ok(()),
            Err(_) => Err("ES is down".into()),
        }
    }

    pub fn new() -> Result<DockerWrapper, Box<Error>> {
        let mut wrapper = DockerWrapper { ip: "".to_string() };
        try!(wrapper.setup());
        Ok(wrapper)
    }
}

fn docker_command(args: &[&'static str]) {
    info!("Running docker {:?}", args);
    let status = Command::new("docker").args(args).status();
    match status {
        Ok(s) => {
            if !s.success() {
                warn!("`docker {a:?}` failed {s}", a = args, s = s)
            }
        }
        Err(e) => warn!("command `docker {a:?}` failed {e}", a = args, e = e),
    }
}

impl Drop for DockerWrapper {
    fn drop(&mut self) {
        if std::env::var("DONT_KILL_THE_WHALE") == Ok("1".to_string()) {
            warn!("the docker won't be stoped at the end, you can debug it.
            Note: ES has been mapped to the port 9242 in you localhost
            manually stop and rm the container mimirsbrunn_tests after debug");
            return;
        }
        docker_command(&["stop", "mimirsbrunn_tests"]);
        docker_command(&["rm", "mimirsbrunn_tests"]);
    }
}
<|endoftext|>