<commit_before>use crate::thread::Time;
use crate::*;
use rustc_target::abi::{Align, Size};
use std::time::{Instant, SystemTime};

/// Implementation of the SYS_futex syscall.
/// `args` is the arguments *after* the syscall number.
pub fn futex<'tcx>(
    this: &mut MiriEvalContext<'_, 'tcx>,
    args: &[OpTy<'tcx, Tag>],
    dest: &PlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
    // The amount of arguments used depends on the type of futex operation.
    // The full futex syscall takes six arguments (excluding the syscall
    // number), which is also the maximum amount of arguments a linux syscall
    // can take on most architectures.
    // However, not all futex operations use all six arguments. The unused ones
    // may or may not be left out from the `syscall()` call.
    // Therefore we don't use `check_arg_count` here, but only check for the
    // number of arguments to fall within a range.
    if args.len() < 3 {
        throw_ub_format!(
            "incorrect number of arguments for `futex` syscall: got {}, expected at least 3",
            args.len()
        );
    }

    // The first three arguments (after the syscall number itself) are the same to all futex operations:
    //     (int *addr, int op, int val).
    // We checked above that these definitely exist.
    let addr = this.read_immediate(&args[0])?;
    let op = this.read_scalar(&args[1])?.to_i32()?;
    let val = this.read_scalar(&args[2])?.to_i32()?;

    let thread = this.get_active_thread();
    let addr_scalar = addr.to_scalar()?;
    let addr_usize = addr_scalar.to_machine_usize(this)?;

    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
    let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
    let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?;
    let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;
    let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET")?;
    let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?;

    // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
    // Miri doesn't support that anyway, so we ignore that flag.
    match op & !futex_private {
        // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
        // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
        // or *timeout expires. `timeout == null` for an infinite timeout.
        //
        // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset)
        // This is identical to FUTEX_WAIT, except:
        //  - The timeout is absolute rather than relative.
        //  - You can specify the bitset to selecting what WAKE operations to respond to.
        op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => {
            let wait_bitset = op & !futex_realtime == futex_wait_bitset;

            let bitset = if wait_bitset {
                if args.len() < 6 {
                    throw_ub_format!(
                        "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6",
                        args.len()
                    );
                }
                let _timeout = this.read_pointer(&args[3])?;
                let _uaddr2 = this.read_pointer(&args[4])?;
                this.read_scalar(&args[5])?.to_u32()?
            } else {
                if args.len() < 4 {
                    throw_ub_format!(
                        "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 4",
                        args.len()
                    );
                }
                u32::MAX
            };

            if bitset == 0 {
                let einval = this.eval_libc("EINVAL")?;
                this.set_last_error(einval)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                return Ok(());
            }

            // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!).
            let timeout = this.ref_to_mplace(&this.read_immediate(&args[3])?)?;
            let timeout_time = if this.ptr_is_null(timeout.ptr)? {
                None
            } else {
                this.check_no_isolation(
                    "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout",
                )?;
                let duration = match this.read_timespec(&timeout)? {
                    Some(duration) => duration,
                    None => {
                        let einval = this.eval_libc("EINVAL")?;
                        this.set_last_error(einval)?;
                        this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                        return Ok(());
                    }
                };
                Some(if wait_bitset {
                    // FUTEX_WAIT_BITSET uses an absolute timestamp.
                    if op & futex_realtime != 0 {
                        Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
                    } else {
                        Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap())
                    }
                } else {
                    // FUTEX_WAIT uses a relative timestamp.
                    if op & futex_realtime != 0 {
                        Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
                    } else {
                        Time::Monotonic(Instant::now().checked_add(duration).unwrap())
                    }
                })
            };
            // Check the pointer for alignment and validity.
            // The API requires `addr` to be a 4-byte aligned pointer, and will
            // use the 4 bytes at the given address as an (atomic) i32.
            this.check_ptr_access_align(
                this.scalar_to_ptr(addr_scalar)?,
                Size::from_bytes(4),
                Align::from_bytes(4).unwrap(),
                CheckInAllocMsg::MemoryAccessTest,
            )?;
            // There may be a concurrent thread changing the value of addr
            // and then invoking the FUTEX_WAKE syscall. It is critical that the
            // effects of this and the other thread are correctly observed,
            // otherwise we will deadlock.
            //
            // There are two scenarios to consider:
            // 1. If we (FUTEX_WAIT) executes first, we'll push ourselves into
            //    the waiters queue and go to sleep. They (addr write & FUTEX_WAKE)
            //    will see us in the queue and wake us up.
            // 2. If they (addr write & FUTEX_WAKE) executes first, we must observe
            //    addr's new value. If we see an outdated value that happens to equal
            //    the expected val, then we'll put ourselves to sleep with no one to wake us
            //    up, so we end up with a deadlock. This is prevented by having a SeqCst
            //    fence inside FUTEX_WAKE syscall, and another SeqCst fence
            //    below, the atomic read on addr after the SeqCst fence is guaranteed
            //    not to see any value older than the addr write immediately before
            //    calling FUTEX_WAKE. We'll see futex_val != val and return without
            //    sleeping.
            //
            //    Note that the fences do not create any happens-before relationship.
            //    The read sees the write immediately before the fence not because
            //    one happens after the other, but is instead due to a guarantee unique
            //    to SeqCst fences that restricts what an atomic read placed AFTER the
            //    fence can see. The read still has to be atomic, otherwise it's a data
            //    race. This guarantee cannot be achieved with acquire-release fences
            //    since they only talk about reads placed BEFORE a fence - and places
            //    no restrictions on what the read itself can see, only that there is
            //    a happens-before between the fences IF the read happens to see the
            //    right value. This is useless to us, since we need the read itself
            //    to see an up-to-date value.
            //
            // It is also critical that the fence, the atomic load, and the comparison
            // altogether happen atomically. If the other thread's fence in FUTEX_WAKE
            // gets interleaved after our fence, then we lose the guarantee on the
            // atomic load being up-to-date; if the other thread's write on addr and FUTEX_WAKE
            // call are interleaved after the load but before the comparison, then we get a TOCTOU
            // race condition, and go to sleep thinking the other thread will wake us up,
            // even though they have already finished.
            //
            // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to
            // do anything special to guarantee fence-load-comparison atomicity.
            this.atomic_fence(&[], AtomicFenceOp::SeqCst)?;
            // Read an `i32` through the pointer, regardless of any wrapper types.
            // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
            // FIXME: this fails if `addr` is not a pointer type.
            let futex_val = this
                .read_scalar_at_offset_atomic(
                    &addr.into(),
                    0,
                    this.machine.layouts.i32,
                    AtomicReadOp::Relaxed,
                )?
                .to_i32()?;
            if val == futex_val {
                // The value still matches, so we block the thread make it wait for FUTEX_WAKE.
                this.block_thread(thread);
                this.futex_wait(addr_usize, thread, bitset);
                // Succesfully waking up from FUTEX_WAIT always returns zero.
                this.write_scalar(Scalar::from_machine_isize(0, this), dest)?;
                // Register a timeout callback if a timeout was specified.
                // This callback will override the return value when the timeout triggers.
                let dest = *dest;
                if let Some(timeout_time) = timeout_time {
                    this.register_timeout_callback(
                        thread,
                        timeout_time,
                        Box::new(move |this| {
                            this.unblock_thread(thread);
                            this.futex_remove_waiter(addr_usize, thread);
                            let etimedout = this.eval_libc("ETIMEDOUT")?;
                            this.set_last_error(etimedout)?;
                            this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?;
                            Ok(())
                        }),
                    );
                }
            } else {
                // The futex value doesn't match the expected value, so we return failure
                // right away without sleeping: -1 and errno set to EAGAIN.
                let eagain = this.eval_libc("EAGAIN")?;
                this.set_last_error(eagain)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
            }
        }
        // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
        // Wakes at most `val` threads waiting on the futex at `addr`.
        // Returns the amount of threads woken up.
        // Does not access the futex value at *addr.
        // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset)
        // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
        op if op == futex_wake || op == futex_wake_bitset => {
            let bitset = if op == futex_wake_bitset {
                if args.len() < 6 {
                    throw_ub_format!(
                        "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6",
                        args.len()
                    );
                }
                let _timeout = this.read_pointer(&args[3])?;
                let _uaddr2 = this.read_pointer(&args[4])?;
                this.read_scalar(&args[5])?.to_u32()?
            } else {
                u32::MAX
            };
            if bitset == 0 {
                let einval = this.eval_libc("EINVAL")?;
                this.set_last_error(einval)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                return Ok(());
            }
            // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
            // will see the latest value on addr which could be changed by our caller
            // before doing the syscall.
            this.atomic_fence(&[], AtomicFenceOp::SeqCst)?;
            let mut n = 0;
            for _ in 0..val {
                if let Some(thread) = this.futex_wake(addr_usize, bitset) {
                    this.unblock_thread(thread);
                    this.unregister_timeout_callback_if_exists(thread);
                    n += 1;
                } else {
                    break;
                }
            }
            this.write_scalar(Scalar::from_machine_isize(n, this), dest)?;
        }
        op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
    }

    Ok(())
}
<commit_msg>tweak correctness comment<commit_after>use crate::thread::Time;
use crate::*;
use rustc_target::abi::{Align, Size};
use std::time::{Instant, SystemTime};

/// Implementation of the SYS_futex syscall.
/// `args` is the arguments *after* the syscall number.
pub fn futex<'tcx>(
    this: &mut MiriEvalContext<'_, 'tcx>,
    args: &[OpTy<'tcx, Tag>],
    dest: &PlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
    // The amount of arguments used depends on the type of futex operation.
    // The full futex syscall takes six arguments (excluding the syscall
    // number), which is also the maximum amount of arguments a linux syscall
    // can take on most architectures.
    // However, not all futex operations use all six arguments. The unused ones
    // may or may not be left out from the `syscall()` call.
    // Therefore we don't use `check_arg_count` here, but only check for the
    // number of arguments to fall within a range.
    if args.len() < 3 {
        throw_ub_format!(
            "incorrect number of arguments for `futex` syscall: got {}, expected at least 3",
            args.len()
        );
    }

    // The first three arguments (after the syscall number itself) are the same to all futex operations:
    //     (int *addr, int op, int val).
    // We checked above that these definitely exist.
    let addr = this.read_immediate(&args[0])?;
    let op = this.read_scalar(&args[1])?.to_i32()?;
    let val = this.read_scalar(&args[2])?.to_i32()?;

    let thread = this.get_active_thread();
    let addr_scalar = addr.to_scalar()?;
    let addr_usize = addr_scalar.to_machine_usize(this)?;

    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
    let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
    let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?;
    let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;
    let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET")?;
    let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?;

    // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
    // Miri doesn't support that anyway, so we ignore that flag.
    match op & !futex_private {
        // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
        // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
        // or *timeout expires. `timeout == null` for an infinite timeout.
        //
        // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset)
        // This is identical to FUTEX_WAIT, except:
        //  - The timeout is absolute rather than relative.
        //  - You can specify the bitset to selecting what WAKE operations to respond to.
        op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => {
            let wait_bitset = op & !futex_realtime == futex_wait_bitset;

            let bitset = if wait_bitset {
                if args.len() < 6 {
                    throw_ub_format!(
                        "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6",
                        args.len()
                    );
                }
                let _timeout = this.read_pointer(&args[3])?;
                let _uaddr2 = this.read_pointer(&args[4])?;
                this.read_scalar(&args[5])?.to_u32()?
            } else {
                if args.len() < 4 {
                    throw_ub_format!(
                        "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 4",
                        args.len()
                    );
                }
                u32::MAX
            };

            if bitset == 0 {
                let einval = this.eval_libc("EINVAL")?;
                this.set_last_error(einval)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                return Ok(());
            }

            // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!).
            let timeout = this.ref_to_mplace(&this.read_immediate(&args[3])?)?;
            let timeout_time = if this.ptr_is_null(timeout.ptr)? {
                None
            } else {
                this.check_no_isolation(
                    "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout",
                )?;
                let duration = match this.read_timespec(&timeout)? {
                    Some(duration) => duration,
                    None => {
                        let einval = this.eval_libc("EINVAL")?;
                        this.set_last_error(einval)?;
                        this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                        return Ok(());
                    }
                };
                Some(if wait_bitset {
                    // FUTEX_WAIT_BITSET uses an absolute timestamp.
                    if op & futex_realtime != 0 {
                        Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
                    } else {
                        Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap())
                    }
                } else {
                    // FUTEX_WAIT uses a relative timestamp.
                    if op & futex_realtime != 0 {
                        Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
                    } else {
                        Time::Monotonic(Instant::now().checked_add(duration).unwrap())
                    }
                })
            };
            // Check the pointer for alignment and validity.
            // The API requires `addr` to be a 4-byte aligned pointer, and will
            // use the 4 bytes at the given address as an (atomic) i32.
            this.check_ptr_access_align(
                this.scalar_to_ptr(addr_scalar)?,
                Size::from_bytes(4),
                Align::from_bytes(4).unwrap(),
                CheckInAllocMsg::MemoryAccessTest,
            )?;
            // There may be a concurrent thread changing the value of addr
            // and then invoking the FUTEX_WAKE syscall. It is critical that the
            // effects of this and the other thread are correctly observed,
            // otherwise we will deadlock.
            //
            // There are two scenarios to consider:
            // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into
            //    the waiters queue and go to sleep. They (addr write & FUTEX_WAKE)
            //    will see us in the queue and wake us up.
            // 2. If they (addr write & FUTEX_WAKE) execute first, we must observe
            //    addr's new value. If we see an outdated value that happens to equal
            //    the expected val, then we'll put ourselves to sleep with no one to wake us
            //    up, so we end up with a deadlock. This is prevented by having a SeqCst
            //    fence inside FUTEX_WAKE syscall, and another SeqCst fence
            //    below, the atomic read on addr after the SeqCst fence is guaranteed
            //    not to see any value older than the addr write immediately before
            //    calling FUTEX_WAKE. We'll see futex_val != val and return without
            //    sleeping.
            //
            //    Note that the fences do not create any happens-before relationship.
            //    The read sees the write immediately before the fence not because
            //    one happens after the other, but is instead due to a guarantee unique
            //    to SeqCst fences that restricts what an atomic read placed AFTER the
            //    fence can see. The read still has to be atomic, otherwise it's a data
            //    race. This guarantee cannot be achieved with acquire-release fences
            //    since they only talk about reads placed BEFORE a fence - and places
            //    no restrictions on what the read itself can see, only that there is
            //    a happens-before between the fences IF the read happens to see the
            //    right value. This is useless to us, since we need the read itself
            //    to see an up-to-date value.
            //
            // The above case distinction is valid since both FUTEX_WAIT and FUTEX_WAKE
            // contain a SeqCst fence, therefore inducting a total order between the operations.
            // It is also critical that the fence, the atomic load, and the comparison in FUTEX_WAIT
            // altogether happen atomically. If the other thread's fence in FUTEX_WAKE
            // gets interleaved after our fence, then we lose the guarantee on the
            // atomic load being up-to-date; if the other thread's write on addr and FUTEX_WAKE
            // call are interleaved after the load but before the comparison, then we get a TOCTOU
            // race condition, and go to sleep thinking the other thread will wake us up,
            // even though they have already finished.
            //
            // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to
            // do anything special to guarantee fence-load-comparison atomicity.
            this.atomic_fence(&[], AtomicFenceOp::SeqCst)?;
            // Read an `i32` through the pointer, regardless of any wrapper types.
            // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
            // FIXME: this fails if `addr` is not a pointer type.
            let futex_val = this
                .read_scalar_at_offset_atomic(
                    &addr.into(),
                    0,
                    this.machine.layouts.i32,
                    AtomicReadOp::Relaxed,
                )?
                .to_i32()?;
            if val == futex_val {
                // The value still matches, so we block the thread make it wait for FUTEX_WAKE.
                this.block_thread(thread);
                this.futex_wait(addr_usize, thread, bitset);
                // Succesfully waking up from FUTEX_WAIT always returns zero.
                this.write_scalar(Scalar::from_machine_isize(0, this), dest)?;
                // Register a timeout callback if a timeout was specified.
                // This callback will override the return value when the timeout triggers.
                let dest = *dest;
                if let Some(timeout_time) = timeout_time {
                    this.register_timeout_callback(
                        thread,
                        timeout_time,
                        Box::new(move |this| {
                            this.unblock_thread(thread);
                            this.futex_remove_waiter(addr_usize, thread);
                            let etimedout = this.eval_libc("ETIMEDOUT")?;
                            this.set_last_error(etimedout)?;
                            this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?;
                            Ok(())
                        }),
                    );
                }
            } else {
                // The futex value doesn't match the expected value, so we return failure
                // right away without sleeping: -1 and errno set to EAGAIN.
                let eagain = this.eval_libc("EAGAIN")?;
                this.set_last_error(eagain)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
            }
        }
        // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
        // Wakes at most `val` threads waiting on the futex at `addr`.
        // Returns the amount of threads woken up.
        // Does not access the futex value at *addr.
        // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset)
        // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
        op if op == futex_wake || op == futex_wake_bitset => {
            let bitset = if op == futex_wake_bitset {
                if args.len() < 6 {
                    throw_ub_format!(
                        "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6",
                        args.len()
                    );
                }
                let _timeout = this.read_pointer(&args[3])?;
                let _uaddr2 = this.read_pointer(&args[4])?;
                this.read_scalar(&args[5])?.to_u32()?
            } else {
                u32::MAX
            };
            if bitset == 0 {
                let einval = this.eval_libc("EINVAL")?;
                this.set_last_error(einval)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                return Ok(());
            }
            // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
            // will see the latest value on addr which could be changed by our caller
            // before doing the syscall.
            this.atomic_fence(&[], AtomicFenceOp::SeqCst)?;
            let mut n = 0;
            for _ in 0..val {
                if let Some(thread) = this.futex_wake(addr_usize, bitset) {
                    this.unblock_thread(thread);
                    this.unregister_timeout_callback_if_exists(thread);
                    n += 1;
                } else {
                    break;
                }
            }
            this.write_scalar(Scalar::from_machine_isize(n, this), dest)?;
        }
        op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
    }

    Ok(())
}
<|endoftext|>


<commit_before>use core::marker::PhantomData;
use core::{cmp, iter, result, slice, str};

use crate::endian::LittleEndian as LE;
use crate::pe;
use crate::read::{
    self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef,
    Relocation, Result, SectionFlags, SectionIndex, SectionKind,
};

use super::{ImageNtHeaders, PeFile, SectionTable};

/// An iterator over the loadable sections of a `PeFile32`.
pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> =
    PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>;
/// An iterator over the loadable sections of a `PeFile64`.
pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> =
    PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>;

/// An iterator over the loadable sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSegmentIterator<'data, 'file, Pe, R = &'data [u8]>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    pub(super) file: &'file PeFile<'data, Pe, R>,
    pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
}

impl<'data, 'file, Pe, R> Iterator for PeSegmentIterator<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    type Item = PeSegment<'data, 'file, Pe, R>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| PeSegment {
            file: self.file,
            section,
        })
    }
}

/// A loadable section of a `PeFile32`.
pub type PeSegment32<'data, 'file, R = &'data [u8]> =
    PeSegment<'data, 'file, pe::ImageNtHeaders32, R>;
/// A loadable section of a `PeFile64`.
pub type PeSegment64<'data, 'file, R = &'data [u8]> =
    PeSegment<'data, 'file, pe::ImageNtHeaders64, R>;

/// A loadable section of a `PeFile`.
#[derive(Debug)]
pub struct PeSegment<'data, 'file, Pe, R = &'data [u8]>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    file: &'file PeFile<'data, Pe, R>,
    section: &'data pe::ImageSectionHeader,
}

impl<'data, 'file, Pe, R> PeSegment<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    fn bytes(&self) -> Result<&'data [u8]> {
        self.section
            .pe_data(self.file.data)
            .read_error("Invalid PE section offset or size")
    }
}

impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
}

impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size.get(LE))
    }

    #[inline]
    fn align(&self) -> u64 {
        self.file.section_alignment()
    }

    #[inline]
    fn file_range(&self) -> (u64, u64) {
        let (offset, size) = self.section.pe_file_range();
        (u64::from(offset), u64::from(size))
    }

    fn data(&self) -> Result<&'data [u8]> {
        self.bytes()
    }

    fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
        Ok(read::util::data_range(
            self.bytes()?,
            self.address(),
            address,
            size,
        ))
    }

    #[inline]
    fn name_bytes(&self) -> Result<Option<&[u8]>> {
        self.section
            .name(self.file.common.symbols.strings())
            .map(Some)
    }

    #[inline]
    fn name(&self) -> Result<Option<&str>> {
        let name = self.section.name(self.file.common.symbols.strings())?;
        Ok(Some(
            str::from_utf8(name)
                .ok()
                .read_error("Non UTF-8 PE section name")?,
        ))
    }
}

/// An iterator over the sections of a `PeFile32`.
pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> =
    PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
/// An iterator over the sections of a `PeFile64`.
pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> =
    PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;

/// An iterator over the sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]>
where
    'data: 'file,
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    pub(super) file: &'file PeFile<'data, Pe, R>,
    pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
}

impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    type Item = PeSection<'data, 'file, Pe, R>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(index, section)| PeSection {
            file: self.file,
            index: SectionIndex(index + 1),
            section,
        })
    }
}

/// A section of a `PeFile32`.
pub type PeSection32<'data, 'file, R = &'data [u8]> =
    PeSection<'data, 'file, pe::ImageNtHeaders32, R>;
/// A section of a `PeFile64`.
pub type PeSection64<'data, 'file, R = &'data [u8]> =
    PeSection<'data, 'file, pe::ImageNtHeaders64, R>;

/// A section of a `PeFile`.
#[derive(Debug)]
pub struct PeSection<'data, 'file, Pe, R = &'data [u8]>
where
    'data: 'file,
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    pub(super) file: &'file PeFile<'data, Pe, R>,
    pub(super) index: SectionIndex,
    pub(super) section: &'data pe::ImageSectionHeader,
}

impl<'data, 'file, Pe, R> PeSection<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    fn bytes(&self) -> Result<&'data [u8]> {
        self.section
            .pe_data(self.file.data)
            .read_error("Invalid PE section offset or size")
    }
}

impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
}

impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    type RelocationIterator = PeRelocationIterator<'data, 'file, R>;

    #[inline]
    fn index(&self) -> SectionIndex {
        self.index
    }

    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size.get(LE))
    }

    #[inline]
    fn align(&self) -> u64 {
        self.file.section_alignment()
    }

    #[inline]
    fn file_range(&self) -> Option<(u64, u64)> {
        let (offset, size) = self.section.pe_file_range();
        if size == 0 {
            None
        } else {
            Some((u64::from(offset), u64::from(size)))
        }
    }

    fn data(&self) -> Result<&'data [u8]> {
        self.bytes()
    }

    fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
        Ok(read::util::data_range(
            self.bytes()?,
            self.address(),
            address,
            size,
        ))
    }

    #[inline]
    fn compressed_file_range(&self) -> Result<CompressedFileRange> {
        Ok(CompressedFileRange::none(self.file_range()))
    }

    #[inline]
    fn compressed_data(&self) -> Result<CompressedData<'data>> {
        self.data().map(CompressedData::none)
    }

    #[inline]
    fn name_bytes(&self) -> Result<&[u8]> {
        self.section.name(self.file.common.symbols.strings())
    }

    #[inline]
    fn name(&self) -> Result<&str> {
        let name = self.name_bytes()?;
        str::from_utf8(name)
            .ok()
            .read_error("Non UTF-8 PE section name")
    }

    #[inline]
    fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
        Ok(None)
    }

    #[inline]
    fn segment_name(&self) -> Result<Option<&str>> {
        Ok(None)
    }

    #[inline]
    fn kind(&self) -> SectionKind {
        self.section.kind()
    }

    fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> {
        PeRelocationIterator(PhantomData)
    }

    fn flags(&self) -> SectionFlags {
        SectionFlags::Coff {
            characteristics: self.section.characteristics.get(LE),
        }
    }
}

impl<'data> SectionTable<'data> {
    /// Return the data at the given virtual address in a PE file.
    pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
        self.iter()
            .filter_map(|section| section.pe_data_at(data, va))
            .next()
    }
}

impl pe::ImageSectionHeader {
    /// Return the offset and size of the section in a PE file.
    ///
    /// Returns `None` for sections that have no data in the file.
    pub fn pe_file_range(&self) -> (u32, u32) {
        // Pointer and size will be zero for uninitialized data; we don't need to validate this.
        let offset = self.pointer_to_raw_data.get(LE);
        let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
        (offset, size)
    }

    /// Return the section data in a PE file.
    pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
        let (offset, size) = self.pe_file_range();
        data.read_bytes_at(offset.into(), size.into())
    }

    /// Return the data at the given virtual address if this section contains it.
    pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
        let section_va = self.virtual_address.get(LE);
        let offset = va.checked_sub(section_va)?;
        let section_data = self.pe_data(data).ok()?;
        section_data.get(offset as usize..)
    }
}

/// An iterator over the relocations in an `PeSection`.
#[derive(Debug)]
pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>(
    PhantomData<(&'data (), &'file (), R)>,
);

impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> {
    type Item = (u64, Relocation);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<commit_msg>Fixed reading PE section data for contiguous sections (#354)<commit_after>use core::marker::PhantomData;
use core::{cmp, iter, result, slice, str};

use crate::endian::LittleEndian as LE;
use crate::pe;
use crate::read::{
    self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef,
    Relocation, Result, SectionFlags, SectionIndex, SectionKind,
};

use super::{ImageNtHeaders, PeFile, SectionTable};

/// An iterator over the loadable sections of a `PeFile32`.
pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> =
    PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>;
/// An iterator over the loadable sections of a `PeFile64`.
pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> =
    PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>;

/// An iterator over the loadable sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSegmentIterator<'data, 'file, Pe, R = &'data [u8]>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    pub(super) file: &'file PeFile<'data, Pe, R>,
    pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
}

impl<'data, 'file, Pe, R> Iterator for PeSegmentIterator<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    type Item = PeSegment<'data, 'file, Pe, R>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| PeSegment {
            file: self.file,
            section,
        })
    }
}

/// A loadable section of a `PeFile32`.
pub type PeSegment32<'data, 'file, R = &'data [u8]> =
    PeSegment<'data, 'file, pe::ImageNtHeaders32, R>;
/// A loadable section of a `PeFile64`.
pub type PeSegment64<'data, 'file, R = &'data [u8]> =
    PeSegment<'data, 'file, pe::ImageNtHeaders64, R>;

/// A loadable section of a `PeFile`.
#[derive(Debug)]
pub struct PeSegment<'data, 'file, Pe, R = &'data [u8]>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    file: &'file PeFile<'data, Pe, R>,
    section: &'data pe::ImageSectionHeader,
}

impl<'data, 'file, Pe, R> PeSegment<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    fn bytes(&self) -> Result<&'data [u8]> {
        self.section
            .pe_data(self.file.data)
            .read_error("Invalid PE section offset or size")
    }
}

impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
}

impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size.get(LE))
    }

    #[inline]
    fn align(&self) -> u64 {
        self.file.section_alignment()
    }

    #[inline]
    fn file_range(&self) -> (u64, u64) {
        let (offset, size) = self.section.pe_file_range();
        (u64::from(offset), u64::from(size))
    }

    fn data(&self) -> Result<&'data [u8]> {
        self.bytes()
    }

    fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
        Ok(read::util::data_range(
            self.bytes()?,
            self.address(),
            address,
            size,
        ))
    }

    #[inline]
    fn name_bytes(&self) -> Result<Option<&[u8]>> {
        self.section
            .name(self.file.common.symbols.strings())
            .map(Some)
    }

    #[inline]
    fn name(&self) -> Result<Option<&str>> {
        let name = self.section.name(self.file.common.symbols.strings())?;
        Ok(Some(
            str::from_utf8(name)
                .ok()
                .read_error("Non UTF-8 PE section name")?,
        ))
    }
}

/// An iterator over the sections of a `PeFile32`.
pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> =
    PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
/// An iterator over the sections of a `PeFile64`.
pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> =
    PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;

/// An iterator over the sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]>
where
    'data: 'file,
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    pub(super) file: &'file PeFile<'data, Pe, R>,
    pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
}

impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    type Item = PeSection<'data, 'file, Pe, R>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(index, section)| PeSection {
            file: self.file,
            index: SectionIndex(index + 1),
            section,
        })
    }
}

/// A section of a `PeFile32`.
pub type PeSection32<'data, 'file, R = &'data [u8]> =
    PeSection<'data, 'file, pe::ImageNtHeaders32, R>;
/// A section of a `PeFile64`.
pub type PeSection64<'data, 'file, R = &'data [u8]> =
    PeSection<'data, 'file, pe::ImageNtHeaders64, R>;

/// A section of a `PeFile`.
#[derive(Debug)]
pub struct PeSection<'data, 'file, Pe, R = &'data [u8]>
where
    'data: 'file,
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    pub(super) file: &'file PeFile<'data, Pe, R>,
    pub(super) index: SectionIndex,
    pub(super) section: &'data pe::ImageSectionHeader,
}

impl<'data, 'file, Pe, R> PeSection<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    fn bytes(&self) -> Result<&'data [u8]> {
        self.section
            .pe_data(self.file.data)
            .read_error("Invalid PE section offset or size")
    }
}

impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
}

impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R>
where
    Pe: ImageNtHeaders,
    R: ReadRef<'data>,
{
    type RelocationIterator = PeRelocationIterator<'data, 'file, R>;

    #[inline]
    fn index(&self) -> SectionIndex {
        self.index
    }

    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size.get(LE))
    }

    #[inline]
    fn align(&self) -> u64 {
        self.file.section_alignment()
    }

    #[inline]
    fn file_range(&self) -> Option<(u64, u64)> {
        let (offset, size) = self.section.pe_file_range();
        if size == 0 {
            None
        } else {
            Some((u64::from(offset), u64::from(size)))
        }
    }

    fn data(&self) -> Result<&'data [u8]> {
        self.bytes()
    }

    fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
        Ok(read::util::data_range(
            self.bytes()?,
            self.address(),
            address,
            size,
        ))
    }

    #[inline]
    fn compressed_file_range(&self) -> Result<CompressedFileRange> {
        Ok(CompressedFileRange::none(self.file_range()))
    }

    #[inline]
    fn compressed_data(&self) -> Result<CompressedData<'data>> {
        self.data().map(CompressedData::none)
    }

    #[inline]
    fn name_bytes(&self) -> Result<&[u8]> {
        self.section.name(self.file.common.symbols.strings())
    }

    #[inline]
    fn name(&self) -> Result<&str> {
        let name = self.name_bytes()?;
        str::from_utf8(name)
            .ok()
            .read_error("Non UTF-8 PE section name")
    }

    #[inline]
    fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
        Ok(None)
    }

    #[inline]
    fn segment_name(&self) -> Result<Option<&str>> {
        Ok(None)
    }

    #[inline]
    fn kind(&self) -> SectionKind {
        self.section.kind()
    }

    fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> {
        PeRelocationIterator(PhantomData)
    }

    fn flags(&self) -> SectionFlags {
        SectionFlags::Coff {
            characteristics: self.section.characteristics.get(LE),
        }
    }
}

impl<'data> SectionTable<'data> {
    /// Return the data at the given virtual address in a PE file.
    pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
        self.iter()
            .filter_map(|section| section.pe_data_at(data, va))
            .next()
    }
}

impl pe::ImageSectionHeader {
    /// Return the offset and size of the section in a PE file.
    ///
    /// Returns `None` for sections that have no data in the file.
    pub fn pe_file_range(&self) -> (u32, u32) {
        // Pointer and size will be zero for uninitialized data; we don't need to validate this.
        let offset = self.pointer_to_raw_data.get(LE);
        let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
        (offset, size)
    }

    /// Return the section data in a PE file.
    pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
        let (offset, size) = self.pe_file_range();
        data.read_bytes_at(offset.into(), size.into())
    }

    /// Return the data at the given virtual address if this section contains it.
    pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
        let section_va = self.virtual_address.get(LE);
        let offset = va.checked_sub(section_va)?;
        let section_data = self.pe_data(data).ok()?;
        if (offset as usize) < section_data.len() {
            section_data.get(offset as usize..)
        } else {
            // We're calling `.get(i..)` with a range. In case i == section_data.len(), this will return Some([]), not None
            None
        }
    }
}

/// An iterator over the relocations in an `PeSection`.
#[derive(Debug)]
pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>(
    PhantomData<(&'data (), &'file (), R)>,
);

impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> {
    type Item = (u64, Relocation);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
use crate::{
	constants::get_default_user_agent,
	log,
	util::errors::{self, WrappedError},
};
use async_trait::async_trait;
use core::panic;
use futures::stream::TryStreamExt;
use hyper::{
	header::{HeaderName, CONTENT_LENGTH},
	http::HeaderValue,
	HeaderMap, StatusCode,
};
use serde::de::DeserializeOwned;
use std::{io, pin::Pin, str::FromStr, task::Poll};
use tokio::{
	fs,
	io::{AsyncRead, AsyncReadExt},
	sync::mpsc,
};
use tokio_util::compat::FuturesAsyncReadCompatExt;

use super::{
	errors::{wrap, AnyError, StatusError},
	io::{copy_async_progress, ReadBuffer, ReportCopyProgress},
};

pub async fn download_into_file<T>(
	filename: &std::path::Path,
	progress: T,
	mut res: SimpleResponse,
) -> Result<fs::File, WrappedError>
where
	T: ReportCopyProgress,
{
	let mut file = fs::File::create(filename)
		.await
		.map_err(|e| errors::wrap(e, "failed to create file"))?;

	let content_length = res
		.headers
		.get(CONTENT_LENGTH)
		.and_then(|h| h.to_str().ok())
		.and_then(|s| s.parse::<u64>().ok())
		.unwrap_or(0);

	copy_async_progress(progress, &mut res.read, &mut file, content_length)
		.await
		.map_err(|e| errors::wrap(e, "failed to download file"))?;

	Ok(file)
}

pub struct SimpleResponse {
	pub status_code: StatusCode,
	pub headers: HeaderMap,
	pub read: Pin<Box<dyn Send + AsyncRead + 'static>>,
	pub url: String,
}

impl SimpleResponse {
	pub fn generic_error(url: String) -> Self {
		let (_, rx) = mpsc::unbounded_channel();
		SimpleResponse {
			url,
			status_code: StatusCode::INTERNAL_SERVER_ERROR,
			headers: HeaderMap::new(),
			read: Box::pin(DelegatedReader::new(rx)),
		}
	}

	/// Converts the response into a StatusError
	pub async fn into_err(mut self) -> StatusError {
		let mut body = String::new();
		self.read.read_to_string(&mut body).await.ok();

		StatusError {
			url: self.url,
			status_code: self.status_code.as_u16(),
			body,
		}
	}

	/// Deserializes the response body as JSON
	pub async fn json<T: DeserializeOwned>(&mut self) -> Result<T, AnyError> {
		let mut buf = vec![];

		// ideally serde would deserialize a stream, but it does not appear that
		// is supported. reqwest itself reads and decodes separately like we do here:
		self.read
			.read_to_end(&mut buf)
			.await
			.map_err(|e| wrap(e, "error reading response"))?;

		let t = serde_json::from_slice(&buf)
			.map_err(|e| wrap(e, format!("error decoding json from {}", self.url)))?;

		Ok(t)
	}
}

/// *Very* simple HTTP implementation. In most cases, this will just delegate to
/// the request library on the server (i.e. `reqwest`) but it can also be used
/// to make update/download requests on the client rather than the server,
/// similar to SSH's `remote.SSH.localServerDownload` setting.
#[async_trait]
pub trait SimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError>;
}

// Implementation of SimpleHttp that uses a reqwest client.
#[derive(Clone)]
pub struct ReqwestSimpleHttp {
	client: reqwest::Client,
}

impl ReqwestSimpleHttp {
	pub fn new() -> Self {
		Self {
			client: reqwest::ClientBuilder::new()
				.user_agent(get_default_user_agent())
				.build()
				.unwrap(),
		}
	}

	pub fn with_client(client: reqwest::Client) -> Self {
		Self { client }
	}
}

#[async_trait]
impl SimpleHttp for ReqwestSimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError> {
		let res = self
			.client
			.request(reqwest::Method::try_from(method).unwrap(), &url)
			.send()
			.await?;

		Ok(SimpleResponse {
			status_code: res.status(),
			headers: res.headers().clone(),
			url,
			read: Box::pin(
				res.bytes_stream()
					.map_err(|e| futures::io::Error::new(futures::io::ErrorKind::Other, e))
					.into_async_read()
					.compat(),
			),
		})
	}
}

enum DelegatedHttpEvent {
	InitResponse {
		status_code: u16,
		headers: Vec<(String, String)>,
	},
	Body(Vec<u8>),
	End,
}

// Handle for a delegated request that allows manually issuing and response.
pub struct DelegatedHttpRequest {
	pub method: &'static str,
	pub url: String,
	ch: mpsc::UnboundedSender<DelegatedHttpEvent>,
}

impl DelegatedHttpRequest {
	pub fn initial_response(&self, status_code: u16, headers: Vec<(String, String)>) {
		self.ch
			.send(DelegatedHttpEvent::InitResponse {
				status_code,
				headers,
			})
			.ok();
	}

	pub fn body(&self, chunk: Vec<u8>) {
		self.ch.send(DelegatedHttpEvent::Body(chunk)).ok();
	}

	pub fn end(self) {}
}

impl Drop for DelegatedHttpRequest {
	fn drop(&mut self) {
		self.ch.send(DelegatedHttpEvent::End).ok();
	}
}

/// Implementation of SimpleHttp that allows manually controlling responses.
#[derive(Clone)]
pub struct DelegatedSimpleHttp {
	start_request: mpsc::Sender<DelegatedHttpRequest>,
	log: log::Logger,
}

impl DelegatedSimpleHttp {
	pub fn new(log: log::Logger) -> (Self, mpsc::Receiver<DelegatedHttpRequest>) {
		let (tx, rx) = mpsc::channel(4);
		(
			DelegatedSimpleHttp {
				log,
				start_request: tx,
			},
			rx,
		)
	}
}

#[async_trait]
impl SimpleHttp for DelegatedSimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError> {
		trace!(self.log, "making delegated request to {}", url);
		let (tx, mut rx) = mpsc::unbounded_channel();
		let sent = self
			.start_request
			.send(DelegatedHttpRequest {
				method,
				url: url.clone(),
				ch: tx,
			})
			.await;

		if sent.is_err() {
			return Ok(SimpleResponse::generic_error(url)); // sender shut down
		}

		match rx.recv().await {
			Some(DelegatedHttpEvent::InitResponse {
				status_code,
				headers,
			}) => {
				trace!(
					self.log,
					"delegated request to {} resulted in status = {}",
					url,
					status_code
				);
				let mut headers_map = HeaderMap::with_capacity(headers.len());
				for (k, v) in &headers {
					if let (Ok(key), Ok(value)) = (
						HeaderName::from_str(&k.to_lowercase()),
						HeaderValue::from_str(v),
					) {
						headers_map.insert(key, value);
					}
				}

				Ok(SimpleResponse {
					url,
					status_code: StatusCode::from_u16(status_code)
						.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
					headers: headers_map,
					read: Box::pin(DelegatedReader::new(rx)),
				})
			}
			Some(DelegatedHttpEvent::End) => Ok(SimpleResponse::generic_error(url)),
			Some(_) => panic!("expected initresponse as first message from delegated http"),
			None => Ok(SimpleResponse::generic_error(url)), // sender shut down
		}
	}
}

struct DelegatedReader {
	receiver: mpsc::UnboundedReceiver<DelegatedHttpEvent>,
	readbuf: ReadBuffer,
}

impl DelegatedReader {
	pub fn new(rx: mpsc::UnboundedReceiver<DelegatedHttpEvent>) -> Self {
		DelegatedReader {
			readbuf: ReadBuffer::default(),
			receiver: rx,
		}
	}
}

impl AsyncRead for DelegatedReader {
	fn poll_read(
		mut self: Pin<&mut Self>,
		cx: &mut std::task::Context<'_>,
		buf: &mut tokio::io::ReadBuf<'_>,
	) -> std::task::Poll<std::io::Result<()>> {
		if let Some((v, s)) = self.readbuf.take_data() {
			return self.readbuf.put_data(buf, v, s);
		}

		match self.receiver.poll_recv(cx) {
			Poll::Ready(Some(DelegatedHttpEvent::Body(msg))) => self.readbuf.put_data(buf, msg, 0),
			Poll::Ready(Some(_)) => Poll::Ready(Ok(())), // EOF
			Poll::Ready(None) => {
				Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, "EOF")))
			}
			Poll::Pending => Poll::Pending,
		}
	}
}

/// Simple http implementation that falls back to delegated http if
/// making a direct reqwest fails.
#[derive(Clone)]
pub struct FallbackSimpleHttp {
	native: ReqwestSimpleHttp,
	delegated: DelegatedSimpleHttp,
}

impl FallbackSimpleHttp {
	pub fn new(native: ReqwestSimpleHttp, delegated: DelegatedSimpleHttp) -> Self {
		FallbackSimpleHttp { native, delegated }
	}

	pub fn native(&self) -> ReqwestSimpleHttp {
		self.native.clone()
	}

	pub fn delegated(&self) -> DelegatedSimpleHttp {
		self.delegated.clone()
	}
}

#[async_trait]
impl SimpleHttp for FallbackSimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError> {
		let r1 = self.native.make_request(method, url.clone()).await;
		if let Ok(res) = r1 {
			if !res.status_code.is_server_error() {
				return Ok(res);
			}
		}

		self.delegated.make_request(method, url).await
	}
}
<commit_msg>fixup! clippy suggestion<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
use crate::{
	constants::get_default_user_agent,
	log,
	util::errors::{self, WrappedError},
};
use async_trait::async_trait;
use core::panic;
use futures::stream::TryStreamExt;
use hyper::{
	header::{HeaderName, CONTENT_LENGTH},
	http::HeaderValue,
	HeaderMap, StatusCode,
};
use serde::de::DeserializeOwned;
use std::{io, pin::Pin, str::FromStr, task::Poll};
use tokio::{
	fs,
	io::{AsyncRead, AsyncReadExt},
	sync::mpsc,
};
use tokio_util::compat::FuturesAsyncReadCompatExt;

use super::{
	errors::{wrap, AnyError, StatusError},
	io::{copy_async_progress, ReadBuffer, ReportCopyProgress},
};

pub async fn download_into_file<T>(
	filename: &std::path::Path,
	progress: T,
	mut res: SimpleResponse,
) -> Result<fs::File, WrappedError>
where
	T: ReportCopyProgress,
{
	let mut file = fs::File::create(filename)
		.await
		.map_err(|e| errors::wrap(e, "failed to create file"))?;

	let content_length = res
		.headers
		.get(CONTENT_LENGTH)
		.and_then(|h| h.to_str().ok())
		.and_then(|s| s.parse::<u64>().ok())
		.unwrap_or(0);

	copy_async_progress(progress, &mut res.read, &mut file, content_length)
		.await
		.map_err(|e| errors::wrap(e, "failed to download file"))?;

	Ok(file)
}

pub struct SimpleResponse {
	pub status_code: StatusCode,
	pub headers: HeaderMap,
	pub read: Pin<Box<dyn Send + AsyncRead + 'static>>,
	pub url: String,
}

impl SimpleResponse {
	pub fn generic_error(url: String) -> Self {
		let (_, rx) = mpsc::unbounded_channel();
		SimpleResponse {
			url,
			status_code: StatusCode::INTERNAL_SERVER_ERROR,
			headers: HeaderMap::new(),
			read: Box::pin(DelegatedReader::new(rx)),
		}
	}

	/// Converts the response into a StatusError
	pub async fn into_err(mut self) -> StatusError {
		let mut body = String::new();
		self.read.read_to_string(&mut body).await.ok();

		StatusError {
			url: self.url,
			status_code: self.status_code.as_u16(),
			body,
		}
	}

	/// Deserializes the response body as JSON
	pub async fn json<T: DeserializeOwned>(&mut self) -> Result<T, AnyError> {
		let mut buf = vec![];

		// ideally serde would deserialize a stream, but it does not appear that
		// is supported. reqwest itself reads and decodes separately like we do here:
		self.read
			.read_to_end(&mut buf)
			.await
			.map_err(|e| wrap(e, "error reading response"))?;

		let t = serde_json::from_slice(&buf)
			.map_err(|e| wrap(e, format!("error decoding json from {}", self.url)))?;

		Ok(t)
	}
}

/// *Very* simple HTTP implementation. In most cases, this will just delegate to
/// the request library on the server (i.e. `reqwest`) but it can also be used
/// to make update/download requests on the client rather than the server,
/// similar to SSH's `remote.SSH.localServerDownload` setting.
#[async_trait]
pub trait SimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError>;
}

// Implementation of SimpleHttp that uses a reqwest client.
#[derive(Clone)]
pub struct ReqwestSimpleHttp {
	client: reqwest::Client,
}

impl ReqwestSimpleHttp {
	pub fn new() -> Self {
		Self {
			client: reqwest::ClientBuilder::new()
				.user_agent(get_default_user_agent())
				.build()
				.unwrap(),
		}
	}

	pub fn with_client(client: reqwest::Client) -> Self {
		Self { client }
	}
}

impl Default for ReqwestSimpleHttp {
	fn default() -> Self {
		Self::new()
	}
}

#[async_trait]
impl SimpleHttp for ReqwestSimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError> {
		let res = self
			.client
			.request(reqwest::Method::try_from(method).unwrap(), &url)
			.send()
			.await?;

		Ok(SimpleResponse {
			status_code: res.status(),
			headers: res.headers().clone(),
			url,
			read: Box::pin(
				res.bytes_stream()
					.map_err(|e| futures::io::Error::new(futures::io::ErrorKind::Other, e))
					.into_async_read()
					.compat(),
			),
		})
	}
}

enum DelegatedHttpEvent {
	InitResponse {
		status_code: u16,
		headers: Vec<(String, String)>,
	},
	Body(Vec<u8>),
	End,
}

// Handle for a delegated request that allows manually issuing and response.
pub struct DelegatedHttpRequest {
	pub method: &'static str,
	pub url: String,
	ch: mpsc::UnboundedSender<DelegatedHttpEvent>,
}

impl DelegatedHttpRequest {
	pub fn initial_response(&self, status_code: u16, headers: Vec<(String, String)>) {
		self.ch
			.send(DelegatedHttpEvent::InitResponse {
				status_code,
				headers,
			})
			.ok();
	}

	pub fn body(&self, chunk: Vec<u8>) {
		self.ch.send(DelegatedHttpEvent::Body(chunk)).ok();
	}

	pub fn end(self) {}
}

impl Drop for DelegatedHttpRequest {
	fn drop(&mut self) {
		self.ch.send(DelegatedHttpEvent::End).ok();
	}
}

/// Implementation of SimpleHttp that allows manually controlling responses.
#[derive(Clone)]
pub struct DelegatedSimpleHttp {
	start_request: mpsc::Sender<DelegatedHttpRequest>,
	log: log::Logger,
}

impl DelegatedSimpleHttp {
	pub fn new(log: log::Logger) -> (Self, mpsc::Receiver<DelegatedHttpRequest>) {
		let (tx, rx) = mpsc::channel(4);
		(
			DelegatedSimpleHttp {
				log,
				start_request: tx,
			},
			rx,
		)
	}
}

#[async_trait]
impl SimpleHttp for DelegatedSimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError> {
		trace!(self.log, "making delegated request to {}", url);
		let (tx, mut rx) = mpsc::unbounded_channel();
		let sent = self
			.start_request
			.send(DelegatedHttpRequest {
				method,
				url: url.clone(),
				ch: tx,
			})
			.await;

		if sent.is_err() {
			return Ok(SimpleResponse::generic_error(url)); // sender shut down
		}

		match rx.recv().await {
			Some(DelegatedHttpEvent::InitResponse {
				status_code,
				headers,
			}) => {
				trace!(
					self.log,
					"delegated request to {} resulted in status = {}",
					url,
					status_code
				);
				let mut headers_map = HeaderMap::with_capacity(headers.len());
				for (k, v) in &headers {
					if let (Ok(key), Ok(value)) = (
						HeaderName::from_str(&k.to_lowercase()),
						HeaderValue::from_str(v),
					) {
						headers_map.insert(key, value);
					}
				}

				Ok(SimpleResponse {
					url,
					status_code: StatusCode::from_u16(status_code)
						.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
					headers: headers_map,
					read: Box::pin(DelegatedReader::new(rx)),
				})
			}
			Some(DelegatedHttpEvent::End) => Ok(SimpleResponse::generic_error(url)),
			Some(_) => panic!("expected initresponse as first message from delegated http"),
			None => Ok(SimpleResponse::generic_error(url)), // sender shut down
		}
	}
}

struct DelegatedReader {
	receiver: mpsc::UnboundedReceiver<DelegatedHttpEvent>,
	readbuf: ReadBuffer,
}

impl DelegatedReader {
	pub fn new(rx: mpsc::UnboundedReceiver<DelegatedHttpEvent>) -> Self {
		DelegatedReader {
			readbuf: ReadBuffer::default(),
			receiver: rx,
		}
	}
}

impl AsyncRead for DelegatedReader {
	fn poll_read(
		mut self: Pin<&mut Self>,
		cx: &mut std::task::Context<'_>,
		buf: &mut tokio::io::ReadBuf<'_>,
	) -> std::task::Poll<std::io::Result<()>> {
		if let Some((v, s)) = self.readbuf.take_data() {
			return self.readbuf.put_data(buf, v, s);
		}

		match self.receiver.poll_recv(cx) {
			Poll::Ready(Some(DelegatedHttpEvent::Body(msg))) => self.readbuf.put_data(buf, msg, 0),
			Poll::Ready(Some(_)) => Poll::Ready(Ok(())), // EOF
			Poll::Ready(None) => {
				Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, "EOF")))
			}
			Poll::Pending => Poll::Pending,
		}
	}
}

/// Simple http implementation that falls back to delegated http if
/// making a direct reqwest fails.
#[derive(Clone)]
pub struct FallbackSimpleHttp {
	native: ReqwestSimpleHttp,
	delegated: DelegatedSimpleHttp,
}

impl FallbackSimpleHttp {
	pub fn new(native: ReqwestSimpleHttp, delegated: DelegatedSimpleHttp) -> Self {
		FallbackSimpleHttp { native, delegated }
	}

	pub fn native(&self) -> ReqwestSimpleHttp {
		self.native.clone()
	}

	pub fn delegated(&self) -> DelegatedSimpleHttp {
		self.delegated.clone()
	}
}

#[async_trait]
impl SimpleHttp for FallbackSimpleHttp {
	async fn make_request(
		&self,
		method: &'static str,
		url: String,
	) -> Result<SimpleResponse, AnyError> {
		let r1 = self.native.make_request(method, url.clone()).await;
		if let Ok(res) = r1 {
			if !res.status_code.is_server_error() {
				return Ok(res);
			}
		}

		self.delegated.make_request(method, url).await
	}
}
<|endoftext|>


<commit_before>// compile-flags:-g

// gdb-command: run

// gdb-command: print slice
// gdbg-check: $1 = struct &[i32](size=3) = {0, 1, 2}
// gdbr-check: $1 = &[i32](size=3) = {0, 1, 2}

// gdb-command: print mut_slice
// gdbg-check: $2 = struct &mut [i32](size=4) = {2, 3, 5, 7}
// gdbr-check: $2 = &mut [i32](size=4) = {2, 3, 5, 7}

// gdb-command: print str_slice
// gdb-check: $3 = "string slice"

// gdb-command: print mut_str_slice
// gdb-check: $4 = "mutable string slice"

// lldb-command: run

// lldb-command: print slice
// lldb-check: (&[i32]) $0 = size=3 { [0] = 0 [1] = 1 [2] = 2 }

// lldb-command: print mut_slice
// lldb-check: (&mut [i32]) $1 = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }

// lldb-command: print str_slice
// lldb-check: (&str) $2 = "string slice" { data_ptr = [...] length = 12 }

// lldb-command: print mut_str_slice
// lldb-check: (&mut str) $3 = "mutable string slice" { data_ptr = [...] length = 20 }

fn b() {}

fn main() {

    let slice: &[i32] = &[0, 1, 2];
    let mut_slice: &mut [i32] = &mut [2, 3, 5, 7];

    let str_slice: &str = "string slice";
    let mut mut_str_slice_buffer = String::from("mutable string slice");
    let mut_str_slice: &mut str = mut_str_slice_buffer.as_mut_str();

    b(); // #break
}
<commit_msg>Ignore Android debugger pretty-printing tests<commit_after>// ignore-android: FIXME(#10381)
// compile-flags:-g

// gdb-command: run

// gdb-command: print slice
// gdbg-check: $1 = struct &[i32](size=3) = {0, 1, 2}
// gdbr-check: $1 = &[i32](size=3) = {0, 1, 2}

// gdb-command: print mut_slice
// gdbg-check: $2 = struct &mut [i32](size=4) = {2, 3, 5, 7}
// gdbr-check: $2 = &mut [i32](size=4) = {2, 3, 5, 7}

// gdb-command: print str_slice
// gdb-check: $3 = "string slice"

// gdb-command: print mut_str_slice
// gdb-check: $4 = "mutable string slice"

// lldb-command: run

// lldb-command: print slice
// lldb-check: (&[i32]) $0 = size=3 { [0] = 0 [1] = 1 [2] = 2 }

// lldb-command: print mut_slice
// lldb-check: (&mut [i32]) $1 = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }

// lldb-command: print str_slice
// lldb-check: (&str) $2 = "string slice" { data_ptr = [...] length = 12 }

// lldb-command: print mut_str_slice
// lldb-check: (&mut str) $3 = "mutable string slice" { data_ptr = [...] length = 20 }

fn b() {}

fn main() {
    let slice: &[i32] = &[0, 1, 2];
    let mut_slice: &mut [i32] = &mut [2, 3, 5, 7];

    let str_slice: &str = "string slice";
    let mut mut_str_slice_buffer = String::from("mutable string slice");
    let mut_str_slice: &mut str = mut_str_slice_buffer.as_mut_str();

    b(); // #break
}
<|endoftext|>


<commit_before>use libc::c_int;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_int, c_char, c_uchar, c_uint, c_void, int16_t, uint8_t};
    use joystick::ll::{SDL_Joystick, SDL_JoystickGUID};

    pub type SDL_bool = c_int;

    pub type SDL_GameController = c_void;

    pub type SDL_GameControllerBindType = c_uint;
    pub const SDL_CONTROLLER_BINDTYPE_NONE: SDL_GameControllerBindType = 0;
    pub const SDL_CONTROLLER_BINDTYPE_BUTTON: SDL_GameControllerBindType = 1;
    pub const SDL_CONTROLLER_BINDTYPE_AXIS: SDL_GameControllerBindType = 2;
    pub const SDL_CONTROLLER_BINDTYPE_HAT: SDL_GameControllerBindType = 3;

    #[allow(dead_code, non_snake_case)]
    #[repr(C)]
    pub struct SDL_GameControllerButtonBind {
        bindType: SDL_GameControllerBindType,
        value: SDL_GameControllerButtonBindData,
    }

    #[allow(dead_code)]
    #[repr(C)]
    pub struct SDL_GameControllerButtonBindData {
        data: [c_uchar, ..8u],
    }

    #[allow(dead_code)]
    pub struct SDL_GameControllerButtonBindDataHat {
        hat: c_int,
        hat_mask: c_int,
    }

    impl SDL_GameControllerButtonBindData {
        pub fn button(&self) -> *const c_int {
            self.data.as_ptr() as *const _
        }
        pub fn axis(&self) -> *const c_int {
            self.data.as_ptr() as *const _
        }
        pub fn hat(&self) -> *const SDL_GameControllerButtonBindDataHat {
            self.data.as_ptr() as *const _
        }
    }

    pub type SDL_GameControllerAxis = c_int;
    pub const SDL_CONTROLLER_AXIS_INVALID: SDL_GameControllerAxis = -1;
    pub const SDL_CONTROLLER_AXIS_LEFTX: SDL_GameControllerAxis = 0;
    pub const SDL_CONTROLLER_AXIS_LEFTY: SDL_GameControllerAxis = 1;
    pub const SDL_CONTROLLER_AXIS_RIGHTX: SDL_GameControllerAxis = 2;
    pub const SDL_CONTROLLER_AXIS_RIGHTY: SDL_GameControllerAxis = 3;
    pub const SDL_CONTROLLER_AXIS_TRIGGERLEFT: SDL_GameControllerAxis = 4;
    pub const SDL_CONTROLLER_AXIS_TRIGGERRIGHT: SDL_GameControllerAxis = 5;
    pub const SDL_CONTROLLER_AXIS_MAX: SDL_GameControllerAxis = 6;

    pub type SDL_GameControllerButton = c_int;
    pub const SDL_CONTROLLER_BUTTON_INVALID: SDL_GameControllerButton = -1;
    pub const SDL_CONTROLLER_BUTTON_A: SDL_GameControllerButton = 0;
    pub const SDL_CONTROLLER_BUTTON_B: SDL_GameControllerButton = 1;
    pub const SDL_CONTROLLER_BUTTON_X: SDL_GameControllerButton = 2;
    pub const SDL_CONTROLLER_BUTTON_Y: SDL_GameControllerButton = 3;
    pub const SDL_CONTROLLER_BUTTON_BACK: SDL_GameControllerButton = 4;
    pub const SDL_CONTROLLER_BUTTON_GUIDE: SDL_GameControllerButton = 5;
    pub const SDL_CONTROLLER_BUTTON_START: SDL_GameControllerButton = 6;
    pub const SDL_CONTROLLER_BUTTON_LEFTSTICK: SDL_GameControllerButton = 7;
    pub const SDL_CONTROLLER_BUTTON_RIGHTSTICK: SDL_GameControllerButton = 8;
    pub const SDL_CONTROLLER_BUTTON_LEFTSHOULDER: SDL_GameControllerButton = 9;
    pub const SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: SDL_GameControllerButton = 10;
    pub const SDL_CONTROLLER_BUTTON_DPAD_UP: SDL_GameControllerButton = 11;
    pub const SDL_CONTROLLER_BUTTON_DPAD_DOWN: SDL_GameControllerButton = 12;
    pub const SDL_CONTROLLER_BUTTON_DPAD_LEFT: SDL_GameControllerButton = 13;
    pub const SDL_CONTROLLER_BUTTON_DPAD_RIGHT: SDL_GameControllerButton = 14;
    pub const SDL_CONTROLLER_BUTTON_MAX: SDL_GameControllerButton = 15;

    extern "C" {
        pub fn SDL_GameControllerAddMapping(mappingString: *const c_char) -> c_int;
        pub fn SDL_GameControllerMappingForGUID(guid: SDL_JoystickGUID) ->
                  *const c_char;
        pub fn SDL_GameControllerMapping(gamecontroller: *const SDL_GameController)
                  -> *const c_char;
        pub fn SDL_IsGameController(joystick_index: c_int) -> SDL_bool;
        pub fn SDL_GameControllerNameForIndex(joystick_index: c_int) ->
                  *const c_char;
        pub fn SDL_GameControllerOpen(joystick_index: c_int) ->
                  *const SDL_GameController;
        pub fn SDL_GameControllerName(gamecontroller: *const SDL_GameController) ->
                  *const c_char;
        pub fn SDL_GameControllerGetAttached(gamecontroller:
                                                       *const SDL_GameController) ->
                  SDL_bool;
        pub fn SDL_GameControllerGetJoystick(gamecontroller:
                                                       *const SDL_GameController) ->
                  *const SDL_Joystick;
        pub fn SDL_GameControllerEventState(state: c_int) -> c_int;
        pub fn SDL_GameControllerUpdate();
        pub fn SDL_GameControllerGetAxisFromString(pchString: *const c_char) ->
                  SDL_GameControllerAxis;
        pub fn SDL_GameControllerGetStringForAxis(axis:
                                                            SDL_GameControllerAxis)
                  -> *const c_char;
        pub fn SDL_GameControllerGetBindForAxis(gamecontroller:
                                                          *const SDL_GameController,
                                                      axis: SDL_GameControllerAxis)
                  -> SDL_GameControllerButtonBind;
        pub fn SDL_GameControllerGetAxis(gamecontroller: *const SDL_GameController,
                                               axis: SDL_GameControllerAxis) ->
                  int16_t;
        pub fn SDL_GameControllerGetButtonFromString(pchString: *const c_char) ->
                  SDL_GameControllerButton;
        pub fn SDL_GameControllerGetStringForButton(button:
                                                          SDL_GameControllerButton)
                  -> *const c_char;
        pub fn SDL_GameControllerGetBindForButton(gamecontroller:
                                                            *const SDL_GameController,
                                                        button:
                                                          SDL_GameControllerButton)
                  -> SDL_GameControllerButtonBind;
        pub fn SDL_GameControllerGetButton(gamecontroller:
                                                     *const SDL_GameController,
                                                 button: SDL_GameControllerButton)
                  -> uint8_t;
        pub fn SDL_GameControllerClose(gamecontroller: *const SDL_GameController);
    }
}

#[deriving(PartialEq)]
#[repr(i32)]
pub enum ControllerAxis {
    Invalid      = ll::SDL_CONTROLLER_AXIS_INVALID,
    LeftX        = ll::SDL_CONTROLLER_AXIS_LEFTX,
    LeftY        = ll::SDL_CONTROLLER_AXIS_LEFTY,
    RightX       = ll::SDL_CONTROLLER_AXIS_RIGHTX,
    RightY       = ll::SDL_CONTROLLER_AXIS_RIGHTY,
    TriggerLeft  = ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
    TriggerRight = ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}

pub fn wrap_controller_axis(bitflags: u8) -> ControllerAxis {
    match bitflags as c_int {
        ll::SDL_CONTROLLER_AXIS_LEFTX        => ControllerAxis::LeftX,
        ll::SDL_CONTROLLER_AXIS_LEFTY        => ControllerAxis::LeftY,
        ll::SDL_CONTROLLER_AXIS_RIGHTX       => ControllerAxis::RightX,
        ll::SDL_CONTROLLER_AXIS_RIGHTY       => ControllerAxis::RightY,
        ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT  => ControllerAxis::TriggerLeft,
        ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => ControllerAxis::TriggerRight,
        _ => panic!("unhandled controller axis")
    }
}

#[deriving(PartialEq)]
#[repr(i32)]
pub enum ControllerButton {
    InvalidButton       = ll::SDL_CONTROLLER_BUTTON_INVALID,
    AButton             = ll::SDL_CONTROLLER_BUTTON_A,
    BButton             = ll::SDL_CONTROLLER_BUTTON_B,
    XButton             = ll::SDL_CONTROLLER_BUTTON_X,
    YButton             = ll::SDL_CONTROLLER_BUTTON_Y,
    BackButton          = ll::SDL_CONTROLLER_BUTTON_BACK,
    GuideButton         = ll::SDL_CONTROLLER_BUTTON_GUIDE,
    StartButton         = ll::SDL_CONTROLLER_BUTTON_START,
    LeftStickButton     = ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
    RightStickButton    = ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    LeftShoulderButton  = ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    RightShoulderButton = ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    DPadUpButton        = ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
    DPadDownButton      = ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    DPadLeftButton      = ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    DPadRightButton     = ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
}

pub fn wrap_controller_button(bitflags: u8) -> ControllerButton {
    match bitflags as c_int {
        ll::SDL_CONTROLLER_BUTTON_A             => ControllerButton::AButton,
        ll::SDL_CONTROLLER_BUTTON_B             => ControllerButton::BButton,
        ll::SDL_CONTROLLER_BUTTON_X             => ControllerButton::XButton,
        ll::SDL_CONTROLLER_BUTTON_Y             => ControllerButton::YButton,
        ll::SDL_CONTROLLER_BUTTON_BACK          => ControllerButton::BackButton,
        ll::SDL_CONTROLLER_BUTTON_GUIDE         => ControllerButton::GuideButton,
        ll::SDL_CONTROLLER_BUTTON_START         => ControllerButton::StartButton,
        ll::SDL_CONTROLLER_BUTTON_LEFTSTICK     => ControllerButton::LeftStickButton,
        ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK    => ControllerButton::RightStickButton,
        ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER  => ControllerButton::LeftShoulderButton,
        ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => ControllerButton::RightShoulderButton,
        ll::SDL_CONTROLLER_BUTTON_DPAD_UP       => ControllerButton::DPadUpButton,
        ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN     => ControllerButton::DPadDownButton,
        ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT     => ControllerButton::DPadLeftButton,
        ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT    => ControllerButton::DPadRightButton,
        _ => panic!("unhandled controller button")
    }
}
<commit_msg>Remove "Button" suffix from ControllerButton enum variants.<commit_after>use libc::c_int;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_int, c_char, c_uchar, c_uint, c_void, int16_t, uint8_t};
    use joystick::ll::{SDL_Joystick, SDL_JoystickGUID};

    pub type SDL_bool = c_int;

    pub type SDL_GameController = c_void;

    pub type SDL_GameControllerBindType = c_uint;
    pub const SDL_CONTROLLER_BINDTYPE_NONE: SDL_GameControllerBindType = 0;
    pub const SDL_CONTROLLER_BINDTYPE_BUTTON: SDL_GameControllerBindType = 1;
    pub const SDL_CONTROLLER_BINDTYPE_AXIS: SDL_GameControllerBindType = 2;
    pub const SDL_CONTROLLER_BINDTYPE_HAT: SDL_GameControllerBindType = 3;

    #[allow(dead_code, non_snake_case)]
    #[repr(C)]
    pub struct SDL_GameControllerButtonBind {
        bindType: SDL_GameControllerBindType,
        value: SDL_GameControllerButtonBindData,
    }

    #[allow(dead_code)]
    #[repr(C)]
    pub struct SDL_GameControllerButtonBindData {
        data: [c_uchar, ..8u],
    }

    #[allow(dead_code)]
    pub struct SDL_GameControllerButtonBindDataHat {
        hat: c_int,
        hat_mask: c_int,
    }

    impl SDL_GameControllerButtonBindData {
        pub fn button(&self) -> *const c_int {
            self.data.as_ptr() as *const _
        }
        pub fn axis(&self) -> *const c_int {
            self.data.as_ptr() as *const _
        }
        pub fn hat(&self) -> *const SDL_GameControllerButtonBindDataHat {
            self.data.as_ptr() as *const _
        }
    }

    pub type SDL_GameControllerAxis = c_int;
    pub const SDL_CONTROLLER_AXIS_INVALID: SDL_GameControllerAxis = -1;
    pub const SDL_CONTROLLER_AXIS_LEFTX: SDL_GameControllerAxis = 0;
    pub const SDL_CONTROLLER_AXIS_LEFTY: SDL_GameControllerAxis = 1;
    pub const SDL_CONTROLLER_AXIS_RIGHTX: SDL_GameControllerAxis = 2;
    pub const SDL_CONTROLLER_AXIS_RIGHTY: SDL_GameControllerAxis = 3;
    pub const SDL_CONTROLLER_AXIS_TRIGGERLEFT: SDL_GameControllerAxis = 4;
    pub const SDL_CONTROLLER_AXIS_TRIGGERRIGHT: SDL_GameControllerAxis = 5;
    pub const SDL_CONTROLLER_AXIS_MAX: SDL_GameControllerAxis = 6;

    pub type SDL_GameControllerButton = c_int;
    pub const SDL_CONTROLLER_BUTTON_INVALID: SDL_GameControllerButton = -1;
    pub const SDL_CONTROLLER_BUTTON_A: SDL_GameControllerButton = 0;
    pub const SDL_CONTROLLER_BUTTON_B: SDL_GameControllerButton = 1;
    pub const SDL_CONTROLLER_BUTTON_X: SDL_GameControllerButton = 2;
    pub const SDL_CONTROLLER_BUTTON_Y: SDL_GameControllerButton = 3;
    pub const SDL_CONTROLLER_BUTTON_BACK: SDL_GameControllerButton = 4;
    pub const SDL_CONTROLLER_BUTTON_GUIDE: SDL_GameControllerButton = 5;
    pub const SDL_CONTROLLER_BUTTON_START: SDL_GameControllerButton = 6;
    pub const SDL_CONTROLLER_BUTTON_LEFTSTICK: SDL_GameControllerButton = 7;
    pub const SDL_CONTROLLER_BUTTON_RIGHTSTICK: SDL_GameControllerButton = 8;
    pub const SDL_CONTROLLER_BUTTON_LEFTSHOULDER: SDL_GameControllerButton = 9;
    pub const SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: SDL_GameControllerButton = 10;
    pub const SDL_CONTROLLER_BUTTON_DPAD_UP: SDL_GameControllerButton = 11;
    pub const SDL_CONTROLLER_BUTTON_DPAD_DOWN: SDL_GameControllerButton = 12;
    pub const SDL_CONTROLLER_BUTTON_DPAD_LEFT: SDL_GameControllerButton = 13;
    pub const SDL_CONTROLLER_BUTTON_DPAD_RIGHT: SDL_GameControllerButton = 14;
    pub const SDL_CONTROLLER_BUTTON_MAX: SDL_GameControllerButton = 15;

    extern "C" {
        pub fn SDL_GameControllerAddMapping(mappingString: *const c_char) -> c_int;
        pub fn SDL_GameControllerMappingForGUID(guid: SDL_JoystickGUID) ->
                  *const c_char;
        pub fn SDL_GameControllerMapping(gamecontroller: *const SDL_GameController)
                  -> *const c_char;
        pub fn SDL_IsGameController(joystick_index: c_int) -> SDL_bool;
        pub fn SDL_GameControllerNameForIndex(joystick_index: c_int) ->
                  *const c_char;
        pub fn SDL_GameControllerOpen(joystick_index: c_int) ->
                  *const SDL_GameController;
        pub fn SDL_GameControllerName(gamecontroller: *const SDL_GameController) ->
                  *const c_char;
        pub fn SDL_GameControllerGetAttached(gamecontroller:
                                                       *const SDL_GameController) ->
                  SDL_bool;
        pub fn SDL_GameControllerGetJoystick(gamecontroller:
                                                       *const SDL_GameController) ->
                  *const SDL_Joystick;
        pub fn SDL_GameControllerEventState(state: c_int) -> c_int;
        pub fn SDL_GameControllerUpdate();
        pub fn SDL_GameControllerGetAxisFromString(pchString: *const c_char) ->
                  SDL_GameControllerAxis;
        pub fn SDL_GameControllerGetStringForAxis(axis:
                                                            SDL_GameControllerAxis)
                  -> *const c_char;
        pub fn SDL_GameControllerGetBindForAxis(gamecontroller:
                                                          *const SDL_GameController,
                                                      axis: SDL_GameControllerAxis)
                  -> SDL_GameControllerButtonBind;
        pub fn SDL_GameControllerGetAxis(gamecontroller: *const SDL_GameController,
                                               axis: SDL_GameControllerAxis) ->
                  int16_t;
        pub fn SDL_GameControllerGetButtonFromString(pchString: *const c_char) ->
                  SDL_GameControllerButton;
        pub fn SDL_GameControllerGetStringForButton(button:
                                                          SDL_GameControllerButton)
                  -> *const c_char;
        pub fn SDL_GameControllerGetBindForButton(gamecontroller:
                                                            *const SDL_GameController,
                                                        button:
                                                          SDL_GameControllerButton)
                  -> SDL_GameControllerButtonBind;
        pub fn SDL_GameControllerGetButton(gamecontroller:
                                                     *const SDL_GameController,
                                                 button: SDL_GameControllerButton)
                  -> uint8_t;
        pub fn SDL_GameControllerClose(gamecontroller: *const SDL_GameController);
    }
}

#[deriving(PartialEq)]
#[repr(i32)]
pub enum ControllerAxis {
    Invalid      = ll::SDL_CONTROLLER_AXIS_INVALID,
    LeftX        = ll::SDL_CONTROLLER_AXIS_LEFTX,
    LeftY        = ll::SDL_CONTROLLER_AXIS_LEFTY,
    RightX       = ll::SDL_CONTROLLER_AXIS_RIGHTX,
    RightY       = ll::SDL_CONTROLLER_AXIS_RIGHTY,
    TriggerLeft  = ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
    TriggerRight = ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}

pub fn wrap_controller_axis(bitflags: u8) -> ControllerAxis {
    match bitflags as c_int {
        ll::SDL_CONTROLLER_AXIS_LEFTX        => ControllerAxis::LeftX,
        ll::SDL_CONTROLLER_AXIS_LEFTY        => ControllerAxis::LeftY,
        ll::SDL_CONTROLLER_AXIS_RIGHTX       => ControllerAxis::RightX,
        ll::SDL_CONTROLLER_AXIS_RIGHTY       => ControllerAxis::RightY,
        ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT  => ControllerAxis::TriggerLeft,
        ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => ControllerAxis::TriggerRight,
        _ => panic!("unhandled controller axis")
    }
}

#[deriving(PartialEq)]
#[repr(i32)]
pub enum ControllerButton {
    Invalid       = ll::SDL_CONTROLLER_BUTTON_INVALID,
    A             = ll::SDL_CONTROLLER_BUTTON_A,
    B             = ll::SDL_CONTROLLER_BUTTON_B,
    X             = ll::SDL_CONTROLLER_BUTTON_X,
    Y             = ll::SDL_CONTROLLER_BUTTON_Y,
    Back          = ll::SDL_CONTROLLER_BUTTON_BACK,
    Guide         = ll::SDL_CONTROLLER_BUTTON_GUIDE,
    Start         = ll::SDL_CONTROLLER_BUTTON_START,
    LeftStick     = ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
    RightStick    = ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    LeftShoulder  = ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    RightShoulder = ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    DPadUp        = ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
    DPadDown      = ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    DPadLeft      = ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    DPadRight     = ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
}

pub fn wrap_controller_button(bitflags: u8) -> ControllerButton {
    match bitflags as c_int {
        ll::SDL_CONTROLLER_BUTTON_A             => ControllerButton::A,
        ll::SDL_CONTROLLER_BUTTON_B             => ControllerButton::B,
        ll::SDL_CONTROLLER_BUTTON_X             => ControllerButton::X,
        ll::SDL_CONTROLLER_BUTTON_Y             => ControllerButton::Y,
        ll::SDL_CONTROLLER_BUTTON_BACK          => ControllerButton::Back,
        ll::SDL_CONTROLLER_BUTTON_GUIDE         => ControllerButton::Guide,
        ll::SDL_CONTROLLER_BUTTON_START         => ControllerButton::Start,
        ll::SDL_CONTROLLER_BUTTON_LEFTSTICK     => ControllerButton::LeftStick,
        ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK    => ControllerButton::RightStick,
        ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER  => ControllerButton::LeftShoulder,
        ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => ControllerButton::RightShoulder,
        ll::SDL_CONTROLLER_BUTTON_DPAD_UP       => ControllerButton::DPadUp,
        ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN     => ControllerButton::DPadDown,
        ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT     => ControllerButton::DPadLeft,
        ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT    => ControllerButton::DPadRight,
        _ => panic!("unhandled controller button")
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about
//! conversions from one type to another. They follow the standard
//! Rust conventions of `as`/`to`/`into`/`from`.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A cheap, reference-to-reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Perform the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Perform the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be
/// expensive.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Perform the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
    /// Perform the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    fn as_ref(&self) -> &str {
        self
    }
}
<commit_msg>s/Perform/Performs/<commit_after>// Copyright 2014 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.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about
//! conversions from one type to another. They follow the standard
//! Rust conventions of `as`/`to`/`into`/`from`.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A cheap, reference-to-reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be
/// expensive.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    fn as_ref(&self) -> &str {
        self
    }
}
<|endoftext|>


<commit_before>// Copyright 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 super::io::net::ip::{IpAddr, Ipv4};

// For setting up tests of the new scheduler
pub fn run_in_newsched_task(f: ~fn()) {
    use cell::Cell;
    use unstable::run_in_bare_thread;
    use super::sched::Task;
    use super::uvio::UvEventLoop;

    let f = Cell(Cell(f));

    do run_in_bare_thread {
        let mut sched = ~UvEventLoop::new_scheduler();
        let f = f.take();
        let task = ~do Task::new(&mut sched.stack_pool) {
            (f.take())();
        };
        sched.task_queue.push_back(task);
        sched.run();
    }
}

/// Create a new task and run it right now
pub fn spawn_immediately(f: ~fn()) {
    use cell::Cell;
    use super::*;
    use super::sched::*;

    let mut sched = local_sched::take();
    let task = ~Task::new(&mut sched.stack_pool, f);
    do sched.switch_running_tasks_and_then(task) |task| {
        let task = Cell(task);
        do local_sched::borrow |sched| {
            sched.task_queue.push_front(task.take());
        }
    }
}

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    unsafe {
        return rust_dbg_next_port() as u16;
    }
    extern {
        fn rust_dbg_next_port() -> ::libc::uintptr_t;
    }
}

/// Get a unique localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
    Ipv4(127, 0, 0, 1, next_test_port())
}
<commit_msg>core::rt: Improve docs for run_in_newsched_task testing function<commit_after>// Copyright 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 super::io::net::ip::{IpAddr, Ipv4};

/// Creates a new scheduler in a new thread and runs a task in it,
/// then waits for the scheduler to exit.
pub fn run_in_newsched_task(f: ~fn()) {
    use cell::Cell;
    use unstable::run_in_bare_thread;
    use super::sched::Task;
    use super::uvio::UvEventLoop;

    let f = Cell(Cell(f));

    do run_in_bare_thread {
        let mut sched = ~UvEventLoop::new_scheduler();
        let f = f.take();
        let task = ~do Task::new(&mut sched.stack_pool) {
            (f.take())();
        };
        sched.task_queue.push_back(task);
        sched.run();
    }
}

/// Create a new task and run it right now
pub fn spawn_immediately(f: ~fn()) {
    use cell::Cell;
    use super::*;
    use super::sched::*;

    let mut sched = local_sched::take();
    let task = ~Task::new(&mut sched.stack_pool, f);
    do sched.switch_running_tasks_and_then(task) |task| {
        let task = Cell(task);
        do local_sched::borrow |sched| {
            sched.task_queue.push_front(task.take());
        }
    }
}

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    unsafe {
        return rust_dbg_next_port() as u16;
    }
    extern {
        fn rust_dbg_next_port() -> ::libc::uintptr_t;
    }
}

/// Get a unique localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
    Ipv4(127, 0, 0, 1, next_test_port())
}
<|endoftext|>