<commit_before>use crate::stream::{FuturesUnordered, StreamExt};
use futures_core::future::Future;
use futures_core::stream::Stream;
use futures_core::task::{Context, Poll};
use pin_project::pin_project;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::iter::FromIterator;
use core::pin::Pin;
use alloc::collections::binary_heap::{BinaryHeap, PeekMut};

#[pin_project]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
struct OrderWrapper<T> {
    #[pin]
    data: T, // A future or a future's output
    index: usize,
}

impl<T> PartialEq for OrderWrapper<T> {
    fn eq(&self, other: &Self) -> bool {
        self.index == other.index
    }
}

impl<T> Eq for OrderWrapper<T> {}

impl<T> PartialOrd for OrderWrapper<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for OrderWrapper<T> {
    fn cmp(&self, other: &Self) -> Ordering {
        // BinaryHeap is a max heap, so compare backwards here.
        other.index.cmp(&self.index)
    }
}

impl<T> Future for OrderWrapper<T>
    where T: Future
{
    type Output = OrderWrapper<T::Output>;

    fn poll(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output> {
        let index = self.index;
        self.project().data.poll(cx)
            .map(|output| OrderWrapper { data: output, index })
    }
}

/// An unbounded queue of futures.
///
/// This "combinator" is similar to `FuturesUnordered`, but it imposes an order
/// on top of the set of futures. While futures in the set will race to
/// completion in parallel, results will only be returned in the order their
/// originating futures were added to the queue.
///
/// Futures are pushed into this queue and their realized values are yielded in
/// order. This structure is optimized to manage a large number of futures.
/// Futures managed by `FuturesOrdered` will only be polled when they generate
/// notifications. This reduces the required amount of work needed to coordinate
/// large numbers of futures.
///
/// When a `FuturesOrdered` is first created, it does not contain any futures.
/// Calling `poll` in this state will result in `Poll::Ready(None))` to be
/// returned. Futures are submitted to the queue using `push`; however, the
/// future will **not** be polled at this point. `FuturesOrdered` will only
/// poll managed futures when `FuturesOrdered::poll` is called. As such, it
/// is important to call `poll` after pushing new futures.
///
/// If `FuturesOrdered::poll` returns `Poll::Ready(None)` this means that
/// the queue is currently not managing any futures. A future may be submitted
/// to the queue at a later time. At that point, a call to
/// `FuturesOrdered::poll` will either return the future's resolved value
/// **or** `Poll::Pending` if the future has not yet completed. When
/// multiple futures are submitted to the queue, `FuturesOrdered::poll` will
/// return `Poll::Pending` until the first future completes, even if
/// some of the later futures have already completed.
///
/// Note that you can create a ready-made `FuturesOrdered` via the
/// [`collect`](Iterator::collect) method, or you can start with an empty queue
/// with the `FuturesOrdered::new` constructor.
///
/// This type is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
#[must_use = "streams do nothing unless polled"]
pub struct FuturesOrdered<T: Future> {
    in_progress_queue: FuturesUnordered<OrderWrapper<T>>,
    queued_outputs: BinaryHeap<OrderWrapper<T::Output>>,
    next_incoming_index: usize,
    next_outgoing_index: usize,
}

impl<T: Future> Unpin for FuturesOrdered<T> {}

impl<Fut: Future> FuturesOrdered<Fut> {
    /// Constructs a new, empty `FuturesOrdered`
    ///
    /// The returned `FuturesOrdered` does not contain any futures and, in this
    /// state, `FuturesOrdered::poll_next` will return `Poll::Ready(None)`.
    pub fn new() -> FuturesOrdered<Fut> {
        FuturesOrdered {
            in_progress_queue: FuturesUnordered::new(),
            queued_outputs: BinaryHeap::new(),
            next_incoming_index: 0,
            next_outgoing_index: 0,
        }
    }

    /// Returns the number of futures contained in the queue.
    ///
    /// This represents the total number of in-flight futures, both
    /// those currently processing and those that have completed but
    /// which are waiting for earlier futures to complete.
    pub fn len(&self) -> usize {
        self.in_progress_queue.len() + self.queued_outputs.len()
    }

    /// Returns `true` if the queue contains no futures
    pub fn is_empty(&self) -> bool {
        self.in_progress_queue.is_empty() && self.queued_outputs.is_empty()
    }

    /// Push a future into the queue.
    ///
    /// This function submits the given future to the internal set for managing.
    /// This function will not call `poll` on the submitted future. The caller
    /// must ensure that `FuturesOrdered::poll` is called in order to receive
    /// task notifications.
    pub fn push(&mut self, future: Fut) {
        let wrapped = OrderWrapper {
            data: future,
            index: self.next_incoming_index,
        };
        self.next_incoming_index += 1;
        self.in_progress_queue.push(wrapped);
    }
}

impl<Fut: Future> Default for FuturesOrdered<Fut> {
    fn default() -> FuturesOrdered<Fut> {
        FuturesOrdered::new()
    }
}

impl<Fut: Future> Stream for FuturesOrdered<Fut> {
    type Item = Fut::Output;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Option<Self::Item>> {
        let this = &mut *self;

        // Check to see if we've already received the next value
        if let Some(next_output) = this.queued_outputs.peek_mut() {
            if next_output.index == this.next_outgoing_index {
                this.next_outgoing_index += 1;
                return Poll::Ready(Some(PeekMut::pop(next_output).data));
            }
        }

        loop {
            match ready!(this.in_progress_queue.poll_next_unpin(cx)) {
                Some(output) => {
                    if output.index == this.next_outgoing_index {
                        this.next_outgoing_index += 1;
                        return Poll::Ready(Some(output.data));
                    } else {
                        this.queued_outputs.push(output)
                    }
                }
                None => return Poll::Ready(None),
            }
        }
    }

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

impl<Fut: Future> Debug for FuturesOrdered<Fut> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "FuturesOrdered {{ ... }}")
    }
}

impl<Fut: Future> FromIterator<Fut> for FuturesOrdered<Fut> {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Fut>,
    {
        let acc = FuturesOrdered::new();
        iter.into_iter().fold(acc, |mut acc, item| { acc.push(item); acc })
    }
}

impl<Fut: Future> Extend<Fut> for FuturesOrdered<Fut> {
    fn extend<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = Fut>,
    {
        for item in iter.into_iter() {
            self.push(item);
        }
    }
}
<commit_msg>Implement `FusedStream` for `FuturesOrdered` (#2205)<commit_after>use crate::stream::{FuturesUnordered, StreamExt};
use futures_core::future::Future;
use futures_core::stream::Stream;
use futures_core::{FusedStream, task::{Context, Poll}};
use pin_project::pin_project;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::iter::FromIterator;
use core::pin::Pin;
use alloc::collections::binary_heap::{BinaryHeap, PeekMut};

#[pin_project]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
struct OrderWrapper<T> {
    #[pin]
    data: T, // A future or a future's output
    index: usize,
}

impl<T> PartialEq for OrderWrapper<T> {
    fn eq(&self, other: &Self) -> bool {
        self.index == other.index
    }
}

impl<T> Eq for OrderWrapper<T> {}

impl<T> PartialOrd for OrderWrapper<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for OrderWrapper<T> {
    fn cmp(&self, other: &Self) -> Ordering {
        // BinaryHeap is a max heap, so compare backwards here.
        other.index.cmp(&self.index)
    }
}

impl<T> Future for OrderWrapper<T>
    where T: Future
{
    type Output = OrderWrapper<T::Output>;

    fn poll(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output> {
        let index = self.index;
        self.project().data.poll(cx)
            .map(|output| OrderWrapper { data: output, index })
    }
}

/// An unbounded queue of futures.
///
/// This "combinator" is similar to `FuturesUnordered`, but it imposes an order
/// on top of the set of futures. While futures in the set will race to
/// completion in parallel, results will only be returned in the order their
/// originating futures were added to the queue.
///
/// Futures are pushed into this queue and their realized values are yielded in
/// order. This structure is optimized to manage a large number of futures.
/// Futures managed by `FuturesOrdered` will only be polled when they generate
/// notifications. This reduces the required amount of work needed to coordinate
/// large numbers of futures.
///
/// When a `FuturesOrdered` is first created, it does not contain any futures.
/// Calling `poll` in this state will result in `Poll::Ready(None))` to be
/// returned. Futures are submitted to the queue using `push`; however, the
/// future will **not** be polled at this point. `FuturesOrdered` will only
/// poll managed futures when `FuturesOrdered::poll` is called. As such, it
/// is important to call `poll` after pushing new futures.
///
/// If `FuturesOrdered::poll` returns `Poll::Ready(None)` this means that
/// the queue is currently not managing any futures. A future may be submitted
/// to the queue at a later time. At that point, a call to
/// `FuturesOrdered::poll` will either return the future's resolved value
/// **or** `Poll::Pending` if the future has not yet completed. When
/// multiple futures are submitted to the queue, `FuturesOrdered::poll` will
/// return `Poll::Pending` until the first future completes, even if
/// some of the later futures have already completed.
///
/// Note that you can create a ready-made `FuturesOrdered` via the
/// [`collect`](Iterator::collect) method, or you can start with an empty queue
/// with the `FuturesOrdered::new` constructor.
///
/// This type is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
#[must_use = "streams do nothing unless polled"]
pub struct FuturesOrdered<T: Future> {
    in_progress_queue: FuturesUnordered<OrderWrapper<T>>,
    queued_outputs: BinaryHeap<OrderWrapper<T::Output>>,
    next_incoming_index: usize,
    next_outgoing_index: usize,
}

impl<T: Future> Unpin for FuturesOrdered<T> {}

impl<Fut: Future> FuturesOrdered<Fut> {
    /// Constructs a new, empty `FuturesOrdered`
    ///
    /// The returned `FuturesOrdered` does not contain any futures and, in this
    /// state, `FuturesOrdered::poll_next` will return `Poll::Ready(None)`.
    pub fn new() -> FuturesOrdered<Fut> {
        FuturesOrdered {
            in_progress_queue: FuturesUnordered::new(),
            queued_outputs: BinaryHeap::new(),
            next_incoming_index: 0,
            next_outgoing_index: 0,
        }
    }

    /// Returns the number of futures contained in the queue.
    ///
    /// This represents the total number of in-flight futures, both
    /// those currently processing and those that have completed but
    /// which are waiting for earlier futures to complete.
    pub fn len(&self) -> usize {
        self.in_progress_queue.len() + self.queued_outputs.len()
    }

    /// Returns `true` if the queue contains no futures
    pub fn is_empty(&self) -> bool {
        self.in_progress_queue.is_empty() && self.queued_outputs.is_empty()
    }

    /// Push a future into the queue.
    ///
    /// This function submits the given future to the internal set for managing.
    /// This function will not call `poll` on the submitted future. The caller
    /// must ensure that `FuturesOrdered::poll` is called in order to receive
    /// task notifications.
    pub fn push(&mut self, future: Fut) {
        let wrapped = OrderWrapper {
            data: future,
            index: self.next_incoming_index,
        };
        self.next_incoming_index += 1;
        self.in_progress_queue.push(wrapped);
    }
}

impl<Fut: Future> Default for FuturesOrdered<Fut> {
    fn default() -> FuturesOrdered<Fut> {
        FuturesOrdered::new()
    }
}

impl<Fut: Future> Stream for FuturesOrdered<Fut> {
    type Item = Fut::Output;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Option<Self::Item>> {
        let this = &mut *self;

        // Check to see if we've already received the next value
        if let Some(next_output) = this.queued_outputs.peek_mut() {
            if next_output.index == this.next_outgoing_index {
                this.next_outgoing_index += 1;
                return Poll::Ready(Some(PeekMut::pop(next_output).data));
            }
        }

        loop {
            match ready!(this.in_progress_queue.poll_next_unpin(cx)) {
                Some(output) => {
                    if output.index == this.next_outgoing_index {
                        this.next_outgoing_index += 1;
                        return Poll::Ready(Some(output.data));
                    } else {
                        this.queued_outputs.push(output)
                    }
                }
                None => return Poll::Ready(None),
            }
        }
    }

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

impl<Fut: Future> Debug for FuturesOrdered<Fut> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "FuturesOrdered {{ ... }}")
    }
}

impl<Fut: Future> FromIterator<Fut> for FuturesOrdered<Fut> {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Fut>,
    {
        let acc = FuturesOrdered::new();
        iter.into_iter().fold(acc, |mut acc, item| { acc.push(item); acc })
    }
}

impl<Fut: Future> FusedStream for FuturesOrdered<Fut> {
    fn is_terminated(&self) -> bool {
        self.in_progress_queue.is_terminated() && self.queued_outputs.is_empty()
    }
}

impl<Fut: Future> Extend<Fut> for FuturesOrdered<Fut> {
    fn extend<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = Fut>,
    {
        for item in iter.into_iter() {
            self.push(item);
        }
    }
}
<|endoftext|>


<commit_before>
use super::complex::c64;
use super::raw_vec::RawVec;
use super::plan::Plan;
use super::enums::*;
use super::r2r::*;

/// Field and Coefficient pair
///
/// - This struct is a wrapper of `Plan`
/// - This struct uses fftw_malloc to enable SIMD optimization in FFTW.
pub struct Pair<A, B> {
    pub field: RawVec<A>,
    pub coef: RawVec<B>,
    logical_size: usize,
    forward: Plan,
    backward: Plan,
}

impl<A, B> Pair<A, B> {
    pub fn forward(&mut self) {
        unsafe {
            self.forward.execute();
        }
    }

    pub fn backward(&mut self) {
        unsafe {
            self.backward.execute();
        }
    }
}

impl Pair<f64, f64> {
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<f64>::new(n);
        let forward = Plan::r2r_1d(n, &mut field, &mut coef, forward(kind), flag);
        let backward = Plan::r2r_1d(n, &mut coef, &mut field, backward(kind), flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: logical_size(n, kind),
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<f64, c64> {
    pub fn r2c_1d(n: usize, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<c64>::new(n);
        let forward = Plan::r2c_1d(n, &mut field, &mut coef, flag);
        let backward = Plan::c2r_1d(n, &mut coef, &mut field, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<c64, c64> {
    pub fn c2c_1d(n: usize, sign: SIGN, flag: FLAG) -> Self {
        let mut field = RawVec::<c64>::new(n);
        let mut coef = RawVec::<c64>::new(n);
        let forward = Plan::c2c_1d(n, &mut field, &mut coef, sign, flag);
        let backward = Plan::c2c_1d(n, &mut coef, &mut field, -sign, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}
<commit_msg>Add noramlizaiton<commit_after>
use super::complex::c64;
use super::raw_vec::RawVec;
use super::plan::Plan;
use super::enums::*;
use super::r2r::*;

use std::ops::MulAssign;

pub struct Pair<A, B> {
    pub field: RawVec<A>,
    pub coef: RawVec<B>,
    logical_size: usize,
    forward: Plan,
    backward: Plan,
}

impl<A, B> Pair<A, B> {
    pub fn forward(&mut self) {
        unsafe {
            self.forward.execute();
        }
    }

    pub fn backward(&mut self) {
        unsafe {
            self.backward.execute();
        }
    }

    pub fn normalize_field_by(&mut self, factor: f64)
        where A: MulAssign<f64>
    {
        for val in self.field.iter_mut() {
            *val *= factor;
        }
    }

    pub fn normalize_coef_by(&mut self, factor: f64)
        where B: MulAssign<f64>
    {
        for val in self.coef.iter_mut() {
            *val *= factor;
        }
    }
}

impl Pair<f64, f64> {
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<f64>::new(n);
        let forward = Plan::r2r_1d(n, &mut field, &mut coef, forward(kind), flag);
        let backward = Plan::r2r_1d(n, &mut coef, &mut field, backward(kind), flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: logical_size(n, kind),
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<f64, c64> {
    pub fn r2c_1d(n: usize, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<c64>::new(n / 2 + 1);
        let forward = Plan::r2c_1d(n, &mut field, &mut coef, flag);
        let backward = Plan::c2r_1d(n, &mut coef, &mut field, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<c64, c64> {
    pub fn c2c_1d(n: usize, sign: SIGN, flag: FLAG) -> Self {
        let mut field = RawVec::<c64>::new(n);
        let mut coef = RawVec::<c64>::new(n);
        let forward = Plan::c2c_1d(n, &mut field, &mut coef, sign, flag);
        let backward = Plan::c2c_1d(n, &mut coef, &mut field, -sign, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::mem;
use std::error::Error;

use byteorder::{ByteOrder, LittleEndian};
use serde_json::value::{Value, Number};

use super::Result as EncodingResult;
use super::Error as EncodingError;
use encoding::{CheckedOffset, Field, Offset};
use encoding::serialize::WriteBufferWrapper;
use encoding::serialize::json::{ExonumJson, ExonumJsonDeserialize};

/// Wrapper for the `f32` type that restricts non-finite
/// (NaN, Infinity, negative zero and subnormal) values.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct F32 {
    value: f32,
}

impl F32 {
    /// Creates a new `F32` instance with the given `value`.
    ///
    /// # Panics
    ///
    /// Panics if given value isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F32;
    ///
    /// let val = F32::new(1.0);
    /// assert_eq!(val.get(), 1.0);
    /// ```
    pub fn new(value: f32) -> Self {
        Self::try_from(value).expect("Unexpected non-finite value")
    }

    /// Creates a new `F32` instance with the given `value`. Returns `None` if the given value
    /// isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F32;
    /// use std::f32;
    ///
    /// let val = F32::try_from(1.0);
    /// assert!(val.is_some());
    ///
    /// let val = F32::try_from(f32::NAN);
    /// assert!(val.is_none());
    /// ```
    pub fn try_from(value: f32) -> Option<Self> {
        if value.is_normal() || (value == 0.0 && value.signum() == 1.0) {
            Some(Self { value })
        } else {
            None
        }
    }

    /// Returns value contained in this wrapper.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F32;
    ///
    /// let wrapper = F32::new(1.0);
    /// let value = wrapper.get();
    /// ```
    pub fn get(&self) -> f32 {
        self.value
    }
}

/// Wrapper for the `f64` type that restricts non-finite
/// (NaN, Infinity, negative zero and subnormal) values.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct F64 {
    value: f64,
}

impl F64 {
    /// Creates a new `F64` instance with the given `value`.
    ///
    /// # Panics
    ///
    /// Panics if given value isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F64;
    ///
    /// let val = F64::new(1.0);
    /// assert_eq!(val.get(), 1.0);
    /// ```
    pub fn new(value: f64) -> Self {
        Self::try_from(value).expect("Unexpected non-finite value")
    }

    /// Creates a new `F64` instance with the given `value`. Returns `None` if the given value
    /// isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F64;
    /// use std::f64;
    ///
    /// let val = F64::try_from(1.0);
    /// assert!(val.is_some());
    ///
    /// let val = F64::try_from(f64::NAN);
    /// assert!(val.is_none());
    /// ```
    pub fn try_from(value: f64) -> Option<Self> {
        if value.is_normal() || (value == 0.0 && value.signum() == 1.0) {
            Some(Self { value })
        } else {
            None
        }
    }

    /// Returns value contained in this wrapper.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F64;
    ///
    /// let wrapper = F64::new(1.0);
    /// let value = wrapper.get();
    /// ```
    pub fn get(&self) -> f64 {
        self.value
    }
}

impl<'a> Field<'a> for F32 {
    fn field_size() -> Offset {
        mem::size_of::<Self>() as Offset
    }

    unsafe fn read(buffer: &'a [u8], from: Offset, to: Offset) -> Self {
        Self::new(LittleEndian::read_f32(&buffer[from as usize..to as usize]))
    }

    fn write(&self, buffer: &mut Vec<u8>, from: Offset, to: Offset) {
        LittleEndian::write_f32(&mut buffer[from as usize..to as usize], self.get());
    }

    fn check(
        buffer: &'a [u8],
        from: CheckedOffset,
        to: CheckedOffset,
        latest_segment: CheckedOffset,
    ) -> EncodingResult {
        debug_assert_eq!((to - from)?.unchecked_offset(), Self::field_size());

        let from = from.unchecked_offset();
        let to = to.unchecked_offset();

        let value = LittleEndian::read_f32(&buffer[from as usize..to as usize]);
        match Self::try_from(value) {
            Some(_) => Ok(latest_segment),
            None => Err(EncodingError::UnsupportedFloat {
                position: from,
                value: f64::from(value),
            }),
        }
    }
}

impl<'a> Field<'a> for F64 {
    fn field_size() -> Offset {
        mem::size_of::<Self>() as Offset
    }

    unsafe fn read(buffer: &'a [u8], from: Offset, to: Offset) -> Self {
        Self::new(LittleEndian::read_f64(&buffer[from as usize..to as usize]))
    }

    fn write(&self, buffer: &mut Vec<u8>, from: Offset, to: Offset) {
        LittleEndian::write_f64(&mut buffer[from as usize..to as usize], self.get());
    }

    fn check(
        buffer: &'a [u8],
        from: CheckedOffset,
        to: CheckedOffset,
        latest_segment: CheckedOffset,
    ) -> EncodingResult {
        debug_assert_eq!((to - from)?.unchecked_offset(), Self::field_size());

        let from = from.unchecked_offset();
        let to = to.unchecked_offset();

        let value = LittleEndian::read_f64(&buffer[from as usize..to as usize]);
        match Self::try_from(value) {
            Some(_) => Ok(latest_segment),
            None => Err(EncodingError::UnsupportedFloat {
                position: from,
                value,
            }),
        }
    }
}

impl ExonumJson for F32 {
    fn deserialize_field<B: WriteBufferWrapper>(
        value: &Value,
        buffer: &mut B,
        from: Offset,
        to: Offset,
    ) -> Result<(), Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        buffer.write(
            from,
            to,
            Self::try_from(number as f32).ok_or(
                "Invalid float value in json",
            )?,
        );
        Ok(())
    }

    fn serialize_field(&self) -> Result<Value, Box<Error + Send + Sync>> {
        Ok(Value::Number(
            Number::from_f64(f64::from(self.get())).ok_or(
                "Can't cast float as json",
            )?,
        ))
    }
}

impl ExonumJsonDeserialize for F32 {
    fn deserialize(value: &Value) -> Result<Self, Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        Ok(Self::try_from(number as f32).ok_or(
            "Invalid float value in json",
        )?)
    }
}

impl ExonumJson for F64 {
    fn deserialize_field<B: WriteBufferWrapper>(
        value: &Value,
        buffer: &mut B,
        from: Offset,
        to: Offset,
    ) -> Result<(), Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        buffer.write(
            from,
            to,
            Self::try_from(number).ok_or("Invalid float value in json")?,
        );
        Ok(())
    }

    fn serialize_field(&self) -> Result<Value, Box<Error + Send + Sync>> {
        Ok(Value::Number(Number::from_f64(self.get()).ok_or(
            "Can't cast float as json",
        )?))
    }
}

impl ExonumJsonDeserialize for F64 {
    fn deserialize(value: &Value) -> Result<Self, Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        Ok(Self::try_from(number).ok_or("Invalid float value in json")?)
    }
}

#[cfg(test)]
mod tests {
    use super::{F32, F64};
    use std::num::FpCategory;
    use std::{f32, f64};
    use std::panic;
    use encoding::fields::Field;
    use byteorder::{LittleEndian, ByteOrder};
    use encoding::Offset;

    fn validate_constructor<T, V, C: Fn(V) -> T>(
        constructor: C,
        value: V,
        buffer: &[u8],
        header_size: Offset,
    ) -> bool
    where
        C: panic::RefUnwindSafe,
        V: panic::UnwindSafe,
        T: for<'r> Field<'r> + PartialEq + ::std::fmt::Debug,
    {
        let constructor_result = panic::catch_unwind(|| constructor(value));
        let check_result =
            <T as Field>::check(&buffer, 0.into(), header_size.into(), header_size.into());
        if constructor_result.is_err() && check_result.is_err() {
            return false;
        } else if constructor_result.is_ok() && check_result.is_ok() {
            let constructed = constructor_result.unwrap();
            let read = unsafe { <T as Field>::read(&buffer, 0, header_size) };
            assert_eq!(constructed, read);
            return true;
        } else {
            panic!("{:?} != {:?}", constructor_result, check_result);
        }
    }

    #[test]
    fn test_f32_encoding() {
        let sub: f32 = 1.1754942e-38;
        assert_eq!(sub.classify(), FpCategory::Subnormal);
        let valid_data = vec![0f32, 3.14, -1.0, 1.0, f32::MAX, f32::MIN];
        let invalid_data = vec![-0.0f32, f32::INFINITY, f32::NEG_INFINITY, f32::NAN, sub];
        let mut buf = vec![0; 4];
        for value in valid_data {
            LittleEndian::write_f32(&mut buf, value);
            assert!(validate_constructor(|v| F32::new(v), value, &buf, 4));
        }
        for value in invalid_data {
            LittleEndian::write_f32(&mut buf, value);
            assert!(!validate_constructor(|v| F32::new(v), value, &buf, 4));
        }
    }

    #[test]
    fn test_f64_encoding() {
        let sub: f64 = 1.1754942e-315;
        assert_eq!(sub.classify(), FpCategory::Subnormal);
        let valid_data = vec![0f64, 3.14, -1.0, 1.0, f64::MAX, f64::MIN];
        let invalid_data = vec![-0.0f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN, sub];
        let mut buf = vec![0; 8];
        for value in valid_data {
            LittleEndian::write_f64(&mut buf, value);
            assert!(validate_constructor(|v| F64::new(v), value, &buf, 8));
        }
        for value in invalid_data {
            LittleEndian::write_f64(&mut buf, value);
            assert!(!validate_constructor(|v| F64::new(v), value, &buf, 8));
        }
    }
}
<commit_msg>Add tests for float-containing structs<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::mem;
use std::error::Error;

use byteorder::{ByteOrder, LittleEndian};
use serde_json::value::{Value, Number};

use super::Result as EncodingResult;
use super::Error as EncodingError;
use encoding::{CheckedOffset, Field, Offset};
use encoding::serialize::WriteBufferWrapper;
use encoding::serialize::json::{ExonumJson, ExonumJsonDeserialize};

/// Wrapper for the `f32` type that restricts non-finite
/// (NaN, Infinity, negative zero and subnormal) values.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct F32 {
    value: f32,
}

impl F32 {
    /// Creates a new `F32` instance with the given `value`.
    ///
    /// # Panics
    ///
    /// Panics if given value isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F32;
    ///
    /// let val = F32::new(1.0);
    /// assert_eq!(val.get(), 1.0);
    /// ```
    pub fn new(value: f32) -> Self {
        Self::try_from(value).expect("Unexpected non-finite value")
    }

    /// Creates a new `F32` instance with the given `value`. Returns `None` if the given value
    /// isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F32;
    /// use std::f32;
    ///
    /// let val = F32::try_from(1.0);
    /// assert!(val.is_some());
    ///
    /// let val = F32::try_from(f32::NAN);
    /// assert!(val.is_none());
    /// ```
    pub fn try_from(value: f32) -> Option<Self> {
        if value.is_normal() || (value == 0.0 && value.signum() == 1.0) {
            Some(Self { value })
        } else {
            None
        }
    }

    /// Returns value contained in this wrapper.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F32;
    ///
    /// let wrapper = F32::new(1.0);
    /// let value = wrapper.get();
    /// ```
    pub fn get(&self) -> f32 {
        self.value
    }
}

/// Wrapper for the `f64` type that restricts non-finite
/// (NaN, Infinity, negative zero and subnormal) values.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct F64 {
    value: f64,
}

impl F64 {
    /// Creates a new `F64` instance with the given `value`.
    ///
    /// # Panics
    ///
    /// Panics if given value isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F64;
    ///
    /// let val = F64::new(1.0);
    /// assert_eq!(val.get(), 1.0);
    /// ```
    pub fn new(value: f64) -> Self {
        Self::try_from(value).expect("Unexpected non-finite value")
    }

    /// Creates a new `F64` instance with the given `value`. Returns `None` if the given value
    /// isn't normal (either `NaN`, `Infinity`, negative zero or `SubNormal`).
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F64;
    /// use std::f64;
    ///
    /// let val = F64::try_from(1.0);
    /// assert!(val.is_some());
    ///
    /// let val = F64::try_from(f64::NAN);
    /// assert!(val.is_none());
    /// ```
    pub fn try_from(value: f64) -> Option<Self> {
        if value.is_normal() || (value == 0.0 && value.signum() == 1.0) {
            Some(Self { value })
        } else {
            None
        }
    }

    /// Returns value contained in this wrapper.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::encoding::F64;
    ///
    /// let wrapper = F64::new(1.0);
    /// let value = wrapper.get();
    /// ```
    pub fn get(&self) -> f64 {
        self.value
    }
}

impl<'a> Field<'a> for F32 {
    fn field_size() -> Offset {
        mem::size_of::<Self>() as Offset
    }

    unsafe fn read(buffer: &'a [u8], from: Offset, to: Offset) -> Self {
        Self::new(LittleEndian::read_f32(&buffer[from as usize..to as usize]))
    }

    fn write(&self, buffer: &mut Vec<u8>, from: Offset, to: Offset) {
        LittleEndian::write_f32(&mut buffer[from as usize..to as usize], self.get());
    }

    fn check(
        buffer: &'a [u8],
        from: CheckedOffset,
        to: CheckedOffset,
        latest_segment: CheckedOffset,
    ) -> EncodingResult {
        debug_assert_eq!((to - from)?.unchecked_offset(), Self::field_size());

        let from = from.unchecked_offset();
        let to = to.unchecked_offset();

        let value = LittleEndian::read_f32(&buffer[from as usize..to as usize]);
        match Self::try_from(value) {
            Some(_) => Ok(latest_segment),
            None => Err(EncodingError::UnsupportedFloat {
                position: from,
                value: f64::from(value),
            }),
        }
    }
}

impl<'a> Field<'a> for F64 {
    fn field_size() -> Offset {
        mem::size_of::<Self>() as Offset
    }

    unsafe fn read(buffer: &'a [u8], from: Offset, to: Offset) -> Self {
        Self::new(LittleEndian::read_f64(&buffer[from as usize..to as usize]))
    }

    fn write(&self, buffer: &mut Vec<u8>, from: Offset, to: Offset) {
        LittleEndian::write_f64(&mut buffer[from as usize..to as usize], self.get());
    }

    fn check(
        buffer: &'a [u8],
        from: CheckedOffset,
        to: CheckedOffset,
        latest_segment: CheckedOffset,
    ) -> EncodingResult {
        debug_assert_eq!((to - from)?.unchecked_offset(), Self::field_size());

        let from = from.unchecked_offset();
        let to = to.unchecked_offset();

        let value = LittleEndian::read_f64(&buffer[from as usize..to as usize]);
        match Self::try_from(value) {
            Some(_) => Ok(latest_segment),
            None => Err(EncodingError::UnsupportedFloat {
                position: from,
                value,
            }),
        }
    }
}

impl ExonumJson for F32 {
    fn deserialize_field<B: WriteBufferWrapper>(
        value: &Value,
        buffer: &mut B,
        from: Offset,
        to: Offset,
    ) -> Result<(), Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        buffer.write(
            from,
            to,
            Self::try_from(number as f32).ok_or(
                "Invalid float value in json",
            )?,
        );
        Ok(())
    }

    fn serialize_field(&self) -> Result<Value, Box<Error + Send + Sync>> {
        Ok(Value::Number(
            Number::from_f64(f64::from(self.get())).ok_or(
                "Can't cast float as json",
            )?,
        ))
    }
}

impl ExonumJsonDeserialize for F32 {
    fn deserialize(value: &Value) -> Result<Self, Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        Ok(Self::try_from(number as f32).ok_or(
            "Invalid float value in json",
        )?)
    }
}

impl ExonumJson for F64 {
    fn deserialize_field<B: WriteBufferWrapper>(
        value: &Value,
        buffer: &mut B,
        from: Offset,
        to: Offset,
    ) -> Result<(), Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        buffer.write(
            from,
            to,
            Self::try_from(number).ok_or("Invalid float value in json")?,
        );
        Ok(())
    }

    fn serialize_field(&self) -> Result<Value, Box<Error + Send + Sync>> {
        Ok(Value::Number(Number::from_f64(self.get()).ok_or(
            "Can't cast float as json",
        )?))
    }
}

impl ExonumJsonDeserialize for F64 {
    fn deserialize(value: &Value) -> Result<Self, Box<Error>> {
        let number = value.as_f64().ok_or("Can't cast json as float")?;
        Ok(Self::try_from(number).ok_or("Invalid float value in json")?)
    }
}

#[cfg(test)]
mod tests {
    use super::{F32, F64};
    use std::num::FpCategory;
    use std::{f32, f64};
    use std::panic;
    use encoding::fields::Field;
    use byteorder::{LittleEndian, ByteOrder};
    use encoding::Offset;

    fn validate_constructor<T, V, C: Fn(V) -> T>(
        constructor: C,
        value: V,
        buffer: &[u8],
        header_size: Offset,
    ) -> bool
    where
        C: panic::RefUnwindSafe,
        V: panic::UnwindSafe,
        T: for<'r> Field<'r> + PartialEq + ::std::fmt::Debug,
    {
        let constructor_result = panic::catch_unwind(|| constructor(value));
        let check_result =
            <T as Field>::check(&buffer, 0.into(), header_size.into(), header_size.into());
        if constructor_result.is_err() && check_result.is_err() {
            return false;
        } else if constructor_result.is_ok() && check_result.is_ok() {
            let constructed = constructor_result.unwrap();
            let read = unsafe { <T as Field>::read(&buffer, 0, header_size) };
            assert_eq!(constructed, read);
            return true;
        } else {
            panic!("{:?} != {:?}", constructor_result, check_result);
        }
    }

    #[test]
    fn test_f32_encoding() {
        let sub: f32 = 1.1754942e-38;
        assert_eq!(sub.classify(), FpCategory::Subnormal);
        let valid_data = vec![0f32, 3.14, -1.0, 1.0, f32::MAX, f32::MIN];
        let invalid_data = vec![-0.0f32, f32::INFINITY, f32::NEG_INFINITY, f32::NAN, sub];
        let mut buf = vec![0; 4];
        for value in valid_data {
            LittleEndian::write_f32(&mut buf, value);
            assert!(validate_constructor(|v| F32::new(v), value, &buf, 4));
        }
        for value in invalid_data {
            LittleEndian::write_f32(&mut buf, value);
            assert!(!validate_constructor(|v| F32::new(v), value, &buf, 4));
        }
    }

    #[test]
    fn test_f64_encoding() {
        let sub: f64 = 1.1754942e-315;
        assert_eq!(sub.classify(), FpCategory::Subnormal);
        let valid_data = vec![0f64, 3.14, -1.0, 1.0, f64::MAX, f64::MIN];
        let invalid_data = vec![-0.0f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN, sub];
        let mut buf = vec![0; 8];
        for value in valid_data {
            LittleEndian::write_f64(&mut buf, value);
            assert!(validate_constructor(|v| F64::new(v), value, &buf, 8));
        }
        for value in invalid_data {
            LittleEndian::write_f64(&mut buf, value);
            assert!(!validate_constructor(|v| F64::new(v), value, &buf, 8));
        }
    }

    #[test]
    #[allow(dead_code)]
    fn test_f32_struct() {
        encoding_struct!(
            struct Msg {
                single_float: F32,
                vec: Vec<F32>,
            }
        );
        let test_vec = vec![F32::new(0.0), F32::new(3.14), F32::new(5.82)];

        let msg = Msg::new(F32::new(0.0), test_vec.clone());
        assert_eq!(msg.single_float().get(), 0.0);
        assert_eq!(msg.vec(), test_vec);
    }

    #[test]
    #[allow(dead_code)]
    fn test_f64_struct() {
        encoding_struct!(
            struct Msg {
                single_float: F64,
                vec: Vec<F64>,
            }
        );

        let test_vec = vec![F64::new(0.0), F64::new(3.14), F64::new(5.82)];

        let msg = Msg::new(F64::new(0.0), test_vec.clone());
        assert_eq!(msg.single_float().get(), 0.0);
        assert_eq!(msg.vec(), test_vec);
    }
}
<|endoftext|>


<commit_before>use libc::{c_void, c_char, c_int, c_uint, c_double};
use std::ffi::CString;
use std::ptr;

pub type POETApplyFn = unsafe extern fn(states: *mut c_void,
                                        num_states: c_uint,
                                        id: c_uint,
                                        last_id: c_uint);

pub type POETCurrentStateFn = unsafe extern fn(states: *const c_void,
                                               num_states: c_uint,
                                               curr_state_id: *mut c_uint) -> i32;

#[link(name = "poet")]
extern {
    /*
     * Core functions - poet.h
     */

    fn poet_init(perf_goal: c_double,
                 num_system_states: c_uint,
                 control_states: *mut POETControlState,
                 apply_states: *mut POETCpuState,
                 apply_func: POETApplyFn,
                 curr_state_func: POETCurrentStateFn,
                 period: c_uint,
                 buffer_depth: c_uint,
                 log_filename: *const c_char) -> *mut c_void;

    fn poet_apply_control(state: *mut c_void,
                          id: u64,
                          perf: c_double,
                          pwr: c_double);

    fn poet_destroy(state: *mut c_void);

    /*
     * Configuration/utility functions - poet_config.h
     */

    fn apply_cpu_config(states: *mut c_void,
                        num_states: c_uint,
                        id: c_uint,
                        last_id: c_uint);

    pub fn get_control_states(path: *const c_char,
                              states: *mut *mut POETControlState,
                              num_states: *mut c_uint) -> c_int;

    pub fn get_cpu_states(path: *const c_char,
                          states: *mut *mut POETCpuState,
                          num_states: *mut c_uint) -> c_int;

    fn get_current_cpu_state(states: *const c_void,
                             num_states: c_uint,
                             curr_state_id: *mut c_uint) -> c_int;

}

#[repr(C)]
pub struct POETControlState {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

impl POETControlState {
    pub fn new() -> Result<(*mut POETControlState, u32), String> {
        let mut control_states = ptr::null_mut();
        let mut num_ctl_states : u32 = 0;
        let res = unsafe {
            get_control_states(ptr::null(),
                               &mut control_states,
                               &mut num_ctl_states)
        };
        if res != 0 {
            return Err("Failed to load control states".to_string());
        }
        Ok((control_states, num_ctl_states))
    }
}

#[repr(C)]
pub struct POETCpuState {
    id: c_uint,
    freq: c_uint,
    cores: c_uint,
}

impl POETCpuState {
    pub fn new() -> Result<(*mut POETCpuState, u32), String> {
        let mut cpu_states = ptr::null_mut();
        let mut num_cpu_states : u32 = 0;
        let res = unsafe {
            get_cpu_states(ptr::null(),
                           &mut cpu_states,
                           &mut num_cpu_states)
        };
        if res != 0 {
            return Err("Failed to load cpu states".to_string());
        }
        Ok((cpu_states, num_cpu_states))
    }
}

pub struct POET {
    pub poet: *mut c_void,
}

impl POET {
    pub fn new(perf_goal: f64,
               control_states: *mut POETControlState,
               cpu_states: *mut POETCpuState,
               num_states: u32,
               apply_func: Option<POETApplyFn>,
               curr_state_func: Option<POETCurrentStateFn>,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&str>) -> Result<POET, String> {
        let apply_func = match apply_func {
            Some(p) => p,
            None => apply_cpu_config,
        };
        let curr_state_func = match curr_state_func {
            Some(p) => p,
            None => get_current_cpu_state,
        };
        let log_filename = match log_filename {
            Some(l) => CString::new(l).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      num_states, control_states, cpu_states,
                      apply_func, curr_state_func,
                      period, buffer_depth, log_filename)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object".to_string());
        }
        Ok(POET { poet: poet, })
    }

    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
        println!("Cleaned up POET");
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{self, c_void};

    #[test]
    fn test_basic() {
        let (control_states, num_ctl_states): (*mut POETControlState, u32) = POETControlState::new().ok().expect("Failed to load control states");
        let (cpu_states, num_cpu_states): (*mut POETCpuState, u32) = POETCpuState::new().ok().expect("Failed to load cpu states");
        if num_ctl_states != num_cpu_states {
            panic!("Number of control and cpu states don't match");
        }
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states, num_ctl_states,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.apply_control(0, 1.0, 1.0);
        unsafe {
            libc::free(control_states as *mut c_void);
            libc::free(cpu_states as *mut c_void);
        }
    }

}
<commit_msg>Don't depend on system configs for tests. Add test for rust function callbacks<commit_after>use libc::{c_void, c_char, c_int, c_uint, c_double};
use std::ffi::CString;
use std::ptr;

pub type POETApplyFn = unsafe extern fn(states: *mut c_void,
                                        num_states: c_uint,
                                        id: c_uint,
                                        last_id: c_uint);

pub type POETCurrentStateFn = unsafe extern fn(states: *const c_void,
                                               num_states: c_uint,
                                               curr_state_id: *mut c_uint) -> i32;

#[link(name = "poet")]
extern {
    /*
     * Core functions - poet.h
     */

    fn poet_init(perf_goal: c_double,
                 num_system_states: c_uint,
                 control_states: *mut POETControlState,
                 apply_states: *mut POETCpuState,
                 apply_func: POETApplyFn,
                 curr_state_func: POETCurrentStateFn,
                 period: c_uint,
                 buffer_depth: c_uint,
                 log_filename: *const c_char) -> *mut c_void;

    fn poet_apply_control(state: *mut c_void,
                          id: u64,
                          perf: c_double,
                          pwr: c_double);

    fn poet_destroy(state: *mut c_void);

    /*
     * Configuration/utility functions - poet_config.h
     */

    fn apply_cpu_config(states: *mut c_void,
                        num_states: c_uint,
                        id: c_uint,
                        last_id: c_uint);

    pub fn get_control_states(path: *const c_char,
                              states: *mut *mut POETControlState,
                              num_states: *mut c_uint) -> c_int;

    pub fn get_cpu_states(path: *const c_char,
                          states: *mut *mut POETCpuState,
                          num_states: *mut c_uint) -> c_int;

    fn get_current_cpu_state(states: *const c_void,
                             num_states: c_uint,
                             curr_state_id: *mut c_uint) -> c_int;

}

#[repr(C)]
pub struct POETControlState {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

impl POETControlState {
    pub fn new() -> Result<(*mut POETControlState, u32), String> {
        let mut control_states = ptr::null_mut();
        let mut num_ctl_states : u32 = 0;
        let res = unsafe {
            get_control_states(ptr::null(),
                               &mut control_states,
                               &mut num_ctl_states)
        };
        if res != 0 {
            return Err("Failed to load control states".to_string());
        }
        Ok((control_states, num_ctl_states))
    }
}

impl Default for POETControlState {
    fn default() -> POETControlState {
        POETControlState {
            id: 0,
            speedup: 1.0,
            cost: 1.0,
        }
    }
}

#[repr(C)]
pub struct POETCpuState {
    id: c_uint,
    freq: c_uint,
    cores: c_uint,
}

impl POETCpuState {
    pub fn new() -> Result<(*mut POETCpuState, u32), String> {
        let mut cpu_states = ptr::null_mut();
        let mut num_cpu_states : u32 = 0;
        let res = unsafe {
            get_cpu_states(ptr::null(),
                           &mut cpu_states,
                           &mut num_cpu_states)
        };
        if res != 0 {
            return Err("Failed to load cpu states".to_string());
        }
        Ok((cpu_states, num_cpu_states))
    }
}

impl Default for POETCpuState {
    fn default() -> POETCpuState {
        POETCpuState {
            id: 0,
            freq: 0,
            cores: 0,
        }
    }
}

pub struct POET {
    pub poet: *mut c_void,
}

impl POET {
    pub fn new(perf_goal: f64,
               control_states: *mut POETControlState,
               cpu_states: *mut POETCpuState,
               num_states: u32,
               apply_func: Option<POETApplyFn>,
               curr_state_func: Option<POETCurrentStateFn>,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&str>) -> Result<POET, String> {
        let apply_func = match apply_func {
            Some(p) => p,
            None => apply_cpu_config,
        };
        let curr_state_func = match curr_state_func {
            Some(p) => p,
            None => get_current_cpu_state,
        };
        let log_filename = match log_filename {
            Some(l) => CString::new(l).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      num_states, control_states, cpu_states,
                      apply_func, curr_state_func,
                      period, buffer_depth, log_filename)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object".to_string());
        }
        Ok(POET { poet: poet, })
    }

    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
        println!("Cleaned up POET");
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};

    #[test]
    fn test_basic() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    unsafe extern fn dummy_apply(_states: *mut c_void,
                                 _num_states: c_uint,
                                 _id: c_uint,
                                 _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    unsafe extern fn dummy_curr_state (_states: *const c_void,
                                       _num_states: c_uint,
                                       _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        // this is actually an invalid value, but forces the apply function to be called
        *_curr_state_id = _num_states;
        0
    }

}
<|endoftext|>


<commit_before>extern crate rustyline;

use std::error::Error as StdError;
use std::fmt;
use std::sync::Mutex;

use self::rustyline::error::ReadlineError;

use base::ast::Typed;
use base::types::Kind;
use vm::api::{IO, Function, WithVM, VMType, Userdata};
use vm::gc::{Gc, Traverseable};
use vm::thread::{Thread, RootStr};

use gluon::{Compiler, new_vm};

fn type_of_expr(args: WithVM<RootStr>) -> IO<Result<String, String>> {
    let WithVM { vm, value: args } = args;
    let mut compiler = Compiler::new().implicit_prelude(false);
    IO::Value(match compiler.typecheck_str(vm, "<repl>", &args, None) {
        Ok((expr, _)) => {
            let env = vm.get_env();
            Ok(format!("{}", expr.env_type_of(&*env)))
        }
        Err(msg) => Err(format!("{}", msg)),
    })
}

fn find_kind(args: WithVM<RootStr>) -> IO<Result<String, String>> {
    let vm = args.vm;
    let args = args.value.trim();
    IO::Value(match vm.find_type_info(args) {
        Ok(ref alias) => {
            let kind = alias.args.iter().rev().fold(Kind::typ(), |acc, arg| {
                Kind::function(arg.kind.clone(), acc)
            });
            Ok(format!("{}", kind))
        }
        Err(err) => Err(format!("{}", err)),
    })
}

fn find_info(args: WithVM<RootStr>) -> IO<Result<String, String>> {
    use std::fmt::Write;
    let vm = args.vm;
    let args = args.value.trim();
    let env = vm.get_env();
    let mut buffer = String::new();
    match env.find_type_info(args) {
        Ok(alias) => {
            // Found a type alias
            let mut fmt = || -> Result<(), ::std::fmt::Error> {
                try!(write!(&mut buffer, "type {}", args));
                for g in &alias.args {
                    try!(write!(&mut buffer, " {}", g.id))
                }
                try!(write!(&mut buffer, " = "));
                match alias.typ {
                    Some(ref typ) => try!(write!(&mut buffer, "{}", typ)),
                    None => try!(write!(&mut buffer, "<abstract>")),
                }
                Ok(())
            };
            fmt().unwrap();
        }
        Err(err) => {
            // Try to find a value at `args` to print its type and documentation comment (if any)
            match env.get_binding(args) {
                Ok((_, typ)) => {
                    write!(&mut buffer, "{}: {}", args, typ).unwrap();
                }
                Err(_) => return IO::Value(Err(format!("{}", err))),
            }
        }
    }
    let maybe_comment = env.get_metadata(args)
        .ok()
        .and_then(|metadata| metadata.comment.as_ref());
    if let Some(comment) = maybe_comment {
        for line in comment.lines() {
            write!(&mut buffer, "\n/// {}", line).unwrap();
        }
    }
    IO::Value(Ok(buffer))
}

struct Editor(Mutex<rustyline::Editor<()>>);

impl fmt::Debug for Editor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Editor(..)")
    }
}

impl VMType for Editor {
    type Type = Editor;
}

impl Traverseable for Editor {
    fn traverse(&self, _: &mut Gc) {}
}

fn new_editor(_: ()) -> Userdata<Editor> {
    let editor = rustyline::Editor::new();
    Userdata(Editor(Mutex::new(editor)))
}

fn readline(editor: &Editor, prompt: &str) -> IO<Option<String>> {
    let mut editor = editor.0.lock().unwrap();
    let input = match editor.readline(prompt) {
        Ok(input) => input,
        Err(ReadlineError::Eof) |
        Err(ReadlineError::Interrupted) => return IO::Value(None),
        Err(err) => return IO::Exception(format!("{}", err)),
    };
    if !input.trim().is_empty() {
        editor.add_history_entry(&input);
    }

    IO::Value(Some(input))
}

fn compile_repl(vm: &Thread) -> Result<(), Box<StdError + Send + Sync>> {

    try!(vm.register_type::<Editor>("Editor", &[]));

    try!(vm.define_global("rustyline",
                          record!(
        new_editor => primitive!(1 new_editor),
        readline => primitive!(2 readline)
    )));
    try!(vm.define_global("repl_prim",
                          record!(
        type_of_expr => primitive!(1 type_of_expr),
        find_info => primitive!(1 find_info),
        find_kind => primitive!(1 find_kind)
    )));
    let mut compiler = Compiler::new();
    try!(compiler.load_file(vm, "std/prelude.glu"));
    try!(compiler.load_file(vm, "std/repl.glu"));
    Ok(())
}

#[allow(dead_code)]
pub fn run() -> Result<(), Box<StdError + Send + Sync>> {
    let vm = new_vm();
    try!(compile_repl(&vm));
    let mut repl: Function<&Thread, fn(()) -> IO<()>> = try!(vm.get_global("std.repl"));
    try!(repl.call(()));
    Ok(())
}

#[cfg(test)]
mod tests {
    use gluon::new_vm;
    use super::compile_repl;
    use vm::api::{IO, FunctionRef};

    #[test]
    fn compile_repl_test() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let repl: Result<FunctionRef<fn(()) -> IO<()>>, _> = vm.get_global("std.repl");
        assert!(repl.is_ok(), "{}", repl.err().unwrap());
    }

    type QueryFn = fn(&'static str) -> IO<Result<String, String>>;

    #[test]
    fn type_of_expr() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let mut type_of: FunctionRef<QueryFn> = vm.get_global("repl_prim.type_of_expr").unwrap();
        assert!(type_of.call("std.prelude.Option").is_ok());
    }

    #[test]
    fn find_kind() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let mut find_kind: FunctionRef<QueryFn> = vm.get_global("repl_prim.find_kind").unwrap();
        assert_eq!(find_kind.call("std.prelude.Option"),
                   Ok(IO::Value(Ok("Type -> Type".into()))));
    }

    #[test]
    fn find_info() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let mut find_info: FunctionRef<QueryFn> = vm.get_global("repl_prim.find_info").unwrap();
        match find_info.call("std.prelude.Option") {
            Ok(IO::Value(Ok(_))) => (),
            x => assert!(false, "{:?}", x),
        }
        match find_info.call("std.prelude.id") {
            Ok(IO::Value(Ok(_))) => (),
            x => assert!(false, "{:?}", x),
        }
        match find_info.call("float") {
            Ok(IO::Value(Ok(_))) => (),
            x => assert!(false, "{:?}", x),
        }
    }
}
<commit_msg>fix(repl): Include the prelude when using `:t`<commit_after>extern crate rustyline;

use std::error::Error as StdError;
use std::fmt;
use std::sync::Mutex;

use self::rustyline::error::ReadlineError;

use base::ast::Typed;
use base::types::Kind;
use vm::api::{IO, Function, WithVM, VMType, Userdata};
use vm::gc::{Gc, Traverseable};
use vm::thread::{Thread, RootStr};

use gluon::{Compiler, new_vm};

fn type_of_expr(args: WithVM<RootStr>) -> IO<Result<String, String>> {
    let WithVM { vm, value: args } = args;
    let mut compiler = Compiler::new();
    IO::Value(match compiler.typecheck_str(vm, "<repl>", &args, None) {
        Ok((expr, _)) => {
            let env = vm.get_env();
            Ok(format!("{}", expr.env_type_of(&*env)))
        }
        Err(msg) => Err(format!("{}", msg)),
    })
}

fn find_kind(args: WithVM<RootStr>) -> IO<Result<String, String>> {
    let vm = args.vm;
    let args = args.value.trim();
    IO::Value(match vm.find_type_info(args) {
        Ok(ref alias) => {
            let kind = alias.args.iter().rev().fold(Kind::typ(), |acc, arg| {
                Kind::function(arg.kind.clone(), acc)
            });
            Ok(format!("{}", kind))
        }
        Err(err) => Err(format!("{}", err)),
    })
}

fn find_info(args: WithVM<RootStr>) -> IO<Result<String, String>> {
    use std::fmt::Write;
    let vm = args.vm;
    let args = args.value.trim();
    let env = vm.get_env();
    let mut buffer = String::new();
    match env.find_type_info(args) {
        Ok(alias) => {
            // Found a type alias
            let mut fmt = || -> Result<(), ::std::fmt::Error> {
                try!(write!(&mut buffer, "type {}", args));
                for g in &alias.args {
                    try!(write!(&mut buffer, " {}", g.id))
                }
                try!(write!(&mut buffer, " = "));
                match alias.typ {
                    Some(ref typ) => try!(write!(&mut buffer, "{}", typ)),
                    None => try!(write!(&mut buffer, "<abstract>")),
                }
                Ok(())
            };
            fmt().unwrap();
        }
        Err(err) => {
            // Try to find a value at `args` to print its type and documentation comment (if any)
            match env.get_binding(args) {
                Ok((_, typ)) => {
                    write!(&mut buffer, "{}: {}", args, typ).unwrap();
                }
                Err(_) => return IO::Value(Err(format!("{}", err))),
            }
        }
    }
    let maybe_comment = env.get_metadata(args)
        .ok()
        .and_then(|metadata| metadata.comment.as_ref());
    if let Some(comment) = maybe_comment {
        for line in comment.lines() {
            write!(&mut buffer, "\n/// {}", line).unwrap();
        }
    }
    IO::Value(Ok(buffer))
}

struct Editor(Mutex<rustyline::Editor<()>>);

impl fmt::Debug for Editor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Editor(..)")
    }
}

impl VMType for Editor {
    type Type = Editor;
}

impl Traverseable for Editor {
    fn traverse(&self, _: &mut Gc) {}
}

fn new_editor(_: ()) -> Userdata<Editor> {
    let editor = rustyline::Editor::new();
    Userdata(Editor(Mutex::new(editor)))
}

fn readline(editor: &Editor, prompt: &str) -> IO<Option<String>> {
    let mut editor = editor.0.lock().unwrap();
    let input = match editor.readline(prompt) {
        Ok(input) => input,
        Err(ReadlineError::Eof) |
        Err(ReadlineError::Interrupted) => return IO::Value(None),
        Err(err) => return IO::Exception(format!("{}", err)),
    };
    if !input.trim().is_empty() {
        editor.add_history_entry(&input);
    }

    IO::Value(Some(input))
}

fn compile_repl(vm: &Thread) -> Result<(), Box<StdError + Send + Sync>> {

    try!(vm.register_type::<Editor>("Editor", &[]));

    try!(vm.define_global("rustyline",
                          record!(
        new_editor => primitive!(1 new_editor),
        readline => primitive!(2 readline)
    )));
    try!(vm.define_global("repl_prim",
                          record!(
        type_of_expr => primitive!(1 type_of_expr),
        find_info => primitive!(1 find_info),
        find_kind => primitive!(1 find_kind)
    )));
    let mut compiler = Compiler::new();
    try!(compiler.load_file(vm, "std/prelude.glu"));
    try!(compiler.load_file(vm, "std/repl.glu"));
    Ok(())
}

#[allow(dead_code)]
pub fn run() -> Result<(), Box<StdError + Send + Sync>> {
    let vm = new_vm();
    try!(compile_repl(&vm));
    let mut repl: Function<&Thread, fn(()) -> IO<()>> = try!(vm.get_global("std.repl"));
    try!(repl.call(()));
    Ok(())
}

#[cfg(test)]
mod tests {
    use gluon::new_vm;
    use super::compile_repl;
    use vm::api::{IO, FunctionRef};

    #[test]
    fn compile_repl_test() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let repl: Result<FunctionRef<fn(()) -> IO<()>>, _> = vm.get_global("std.repl");
        assert!(repl.is_ok(), "{}", repl.err().unwrap());
    }

    type QueryFn = fn(&'static str) -> IO<Result<String, String>>;

    #[test]
    fn type_of_expr() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let mut type_of: FunctionRef<QueryFn> = vm.get_global("repl_prim.type_of_expr").unwrap();
        assert!(type_of.call("std.prelude.Option").is_ok());
    }

    #[test]
    fn find_kind() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let mut find_kind: FunctionRef<QueryFn> = vm.get_global("repl_prim.find_kind").unwrap();
        assert_eq!(find_kind.call("std.prelude.Option"),
                   Ok(IO::Value(Ok("Type -> Type".into()))));
    }

    #[test]
    fn find_info() {
        let _ = ::env_logger::init();
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
        let mut find_info: FunctionRef<QueryFn> = vm.get_global("repl_prim.find_info").unwrap();
        match find_info.call("std.prelude.Option") {
            Ok(IO::Value(Ok(_))) => (),
            x => assert!(false, "{:?}", x),
        }
        match find_info.call("std.prelude.id") {
            Ok(IO::Value(Ok(_))) => (),
            x => assert!(false, "{:?}", x),
        }
        match find_info.call("float") {
            Ok(IO::Value(Ok(_))) => (),
            x => assert!(false, "{:?}", x),
        }
    }
}
<|endoftext|>


<commit_before>use reqwest::Response;
use reqwest::header::{Link, LinkValue, RelationType};
use serde_json::{self, Value};

use error::Result;

pub struct Tags {
    next: Option<String>,
    value: Value,
}

fn get_next_page_url_from_response(response: &Response) -> Option<String> {
    let link_header: &Link = try_option!(response.headers().get());
    let value = link_header.values().iter().find(|link_value| {
        let rels = match link_value.rel() {
            Some(rels) => rels,
            None => return false,
        };

        rels.iter().any(|rel| *rel == RelationType::Next)
    });

    value.and_then(LinkValue::anchor).map(|s| s.to_string())
}

impl Tags {
    pub fn from_response(response: Response) -> Result<Self> {
       Ok(Tags {
           next: get_next_page_url_from_response(&response),
           value: serde_json::from_reader(response)?,
       })
    }

    pub fn next_page_url(self) -> Option<String> {
        self.next
    }

    pub fn get_value(&self) -> &Value {
        &self.value
    }
}
<commit_msg>rustfmt fixes<commit_after>use reqwest::Response;
use reqwest::header::{Link, LinkValue, RelationType};
use serde_json::{self, Value};

use error::Result;

pub struct Tags {
    next: Option<String>,
    value: Value,
}

fn get_next_page_url_from_response(response: &Response) -> Option<String> {
    let link_header: &Link = try_option!(response.headers().get());
    let value = link_header.values().iter().find(|link_value| {
        let rels = match link_value.rel() {
            Some(rels) => rels,
            None => return false,
        };

        rels.iter().any(|rel| *rel == RelationType::Next)
    });

    value.and_then(LinkValue::anchor).map(|s| s.to_string())
}

impl Tags {
    pub fn from_response(response: Response) -> Result<Self> {
        Ok(Tags {
            next: get_next_page_url_from_response(&response),
            value: serde_json::from_reader(response)?,
        })
    }

    pub fn next_page_url(self) -> Option<String> {
        self.next
    }

    pub fn get_value(&self) -> &Value {
        &self.value
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate tungsten;

use std::thread;
use std::io::Read;
use hyper::status::StatusCode;
use hyper::client::Client;
use tungsten::server::Tungsten;

fn serve() {
  thread::Builder::new().name(String::from("test-server")).spawn(move || {
    let mut server = Tungsten::new();
    server.listen("0.0.0.0:4040");
  });
}

#[test]
fn test_hello_world() {
    serve();
    let client = Client::new();
    let mut res = client.get("http://0.0.0.0:4040").send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body);

    assert_eq!(res.status, StatusCode::Ok);
    assert_eq!(body, "Hello World!");
}
<commit_msg>silence unused result warnings<commit_after>extern crate hyper;
extern crate tungsten;

use std::thread;
use std::io::Read;
use hyper::status::StatusCode;
use hyper::client::Client;
use tungsten::server::Tungsten;

fn serve() {
  let _ = thread::Builder::new().name(String::from("test-server")).spawn(move || {
    let mut server = Tungsten::new();
    server.listen("0.0.0.0:4040");
  });
}

#[test]
fn test_hello_world() {
    serve();
    let client = Client::new();
    let mut res = client.get("http://0.0.0.0:4040").send().unwrap();
    let mut body = String::new();
    let _ = res.read_to_string(&mut body);

    assert_eq!(res.status, StatusCode::Ok);
    assert_eq!(body, "Hello World!");
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::IpcSender;
use opts;
use serde::Serialize;
use std::any::Any;
use std::borrow::ToOwned;
use std::io::{Write, stderr};
use std::panic::{PanicInfo, take_hook, set_hook};
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::Builder;
use thread_state;

pub type PanicReason = Option<String>;

pub fn spawn_named<F>(name: String, f: F)
    where F: FnOnce() + Send + 'static
{
    let builder = thread::Builder::new().name(name);

    if opts::get().full_backtraces {
        builder.spawn(f).unwrap();
        return;
    }

    let f_with_hook = move || {
        let hook = take_hook();

        let new_hook = move |info: &PanicInfo| {
            let payload = info.payload();
            if let Some(s) = payload.downcast_ref::<String>() {
                if s.contains("SendError") {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `SendError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                } else if s.contains("RecvError")  {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `RecvError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                }
            }
            hook(&info);
        };
        set_hook(Box::new(new_hook));
        f();
    };

    builder.spawn(f_with_hook).unwrap();
}

pub trait AddFailureDetails {
    fn add_panic_message(&mut self, message: String);
    fn add_panic_object(&mut self, object: Box<Any>) {
        if let Some(message) = object.downcast_ref::<String>() {
            self.add_panic_message(message.to_owned());
        } else if let Some(&message) = object.downcast_ref::<&'static str>() {
            self.add_panic_message(message.to_owned());
        }
    }
}

/// An abstraction over `Sender<T>` and `IpcSender<T>`, for use in
/// `spawn_named_with_send_on_failure`.
pub trait SendOnFailure {
    type Value;
    fn send_on_failure(&mut self, value: Self::Value);
}

impl<T> SendOnFailure for Sender<T> where T: Send + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

impl<T> SendOnFailure for IpcSender<T> where T: Send + Serialize + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

/// Arrange to send a particular message to a channel if the thread fails.
pub fn spawn_named_with_send_on_failure<F, T, S>(name: String,
                                                 state: thread_state::ThreadState,
                                                 f: F,
                                                 mut msg: T,
                                                 mut dest: S)
    where F: FnOnce() + Send + 'static,
          T: Send + AddFailureDetails + 'static,
          S: Send + SendOnFailure + 'static,
          S::Value: From<T>,
{
    let future_handle = thread::Builder::new().name(name.to_owned()).spawn(move || {
        thread_state::initialize(state);
        f()
    }).unwrap();

    let watcher_name = format!("{}Watcher", name);
    Builder::new().name(watcher_name).spawn(move || {
        match future_handle.join() {
            Ok(()) => (),
            Err(err) => {
                debug!("{} failed, notifying constellation", name);
                msg.add_panic_object(err);
                dest.send_on_failure(S::Value::from(msg));
            }
        }
    }).unwrap();
}
<commit_msg>Auto merge of #10609 - asajeffrey:add-panic-object-borrows, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::IpcSender;
use opts;
use serde::Serialize;
use std::any::Any;
use std::borrow::ToOwned;
use std::io::{Write, stderr};
use std::panic::{PanicInfo, take_hook, set_hook};
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::Builder;
use thread_state;

pub type PanicReason = Option<String>;

pub fn spawn_named<F>(name: String, f: F)
    where F: FnOnce() + Send + 'static
{
    let builder = thread::Builder::new().name(name);

    if opts::get().full_backtraces {
        builder.spawn(f).unwrap();
        return;
    }

    let f_with_hook = move || {
        let hook = take_hook();

        let new_hook = move |info: &PanicInfo| {
            let payload = info.payload();
            if let Some(s) = payload.downcast_ref::<String>() {
                if s.contains("SendError") {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `SendError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                } else if s.contains("RecvError")  {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `RecvError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                }
            }
            hook(&info);
        };
        set_hook(Box::new(new_hook));
        f();
    };

    builder.spawn(f_with_hook).unwrap();
}

pub trait AddFailureDetails {
    fn add_panic_message(&mut self, message: String);
    fn add_panic_object(&mut self, object: &Any) {
        if let Some(message) = object.downcast_ref::<String>() {
            self.add_panic_message(message.to_owned());
        } else if let Some(&message) = object.downcast_ref::<&'static str>() {
            self.add_panic_message(message.to_owned());
        }
    }
}

/// An abstraction over `Sender<T>` and `IpcSender<T>`, for use in
/// `spawn_named_with_send_on_failure`.
pub trait SendOnFailure {
    type Value;
    fn send_on_failure(&mut self, value: Self::Value);
}

impl<T> SendOnFailure for Sender<T> where T: Send + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

impl<T> SendOnFailure for IpcSender<T> where T: Send + Serialize + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

/// Arrange to send a particular message to a channel if the thread fails.
pub fn spawn_named_with_send_on_failure<F, T, S>(name: String,
                                                 state: thread_state::ThreadState,
                                                 f: F,
                                                 mut msg: T,
                                                 mut dest: S)
    where F: FnOnce() + Send + 'static,
          T: Send + AddFailureDetails + 'static,
          S: Send + SendOnFailure + 'static,
          S::Value: From<T>,
{
    let future_handle = thread::Builder::new().name(name.to_owned()).spawn(move || {
        thread_state::initialize(state);
        f()
    }).unwrap();

    let watcher_name = format!("{}Watcher", name);
    Builder::new().name(watcher_name).spawn(move || {
        match future_handle.join() {
            Ok(()) => (),
            Err(err) => {
                debug!("{} failed, notifying constellation", name);
                msg.add_panic_object(&*err);
                dest.send_on_failure(S::Value::from(msg));
            }
        }
    }).unwrap();
}
<|endoftext|>


<commit_before>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use glutin::GlContext;
use std;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<glutin::GlWindow>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<glutin::GlWindow>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new(
        window_builder: glutin::WindowBuilder,
        context_builder: glutin::ContextBuilder,
        events_loop: &glutin::EventsLoop,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = try!(glutin::GlWindow::new(window_builder, context_builder, events_loop));
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window(gl_window: glutin::GlWindow) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked(gl_window: glutin::GlWindow) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug(gl_window: glutin::GlWindow, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug(
        gl_window: glutin::GlWindow,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner(
        gl_window: glutin::GlWindow,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = Rc::new(RefCell::new(gl_window));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = try!(unsafe { context::Context::new(glutin_backend, checked, debug) });
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `GlWindow` with the given window and context builders.
    ///
    /// This method ensures that the new `GlWindow`'s `Context` will share the display lists of the
    /// original `GlWindow`'s `Context`.
    pub fn rebuild(
        &self,
        window_builder: glutin::WindowBuilder,
        context_builder: glutin::ContextBuilder,
        events_loop: &glutin::EventsLoop,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let context_builder = context_builder.with_shared_lists(gl_window.context());
            try!(glutin::GlWindow::new(window_builder, context_builder, events_loop))
        };

        // Replace the stored GlWindow with the new one.
        let mut gl_window = self.gl_window.borrow_mut();
        std::mem::replace(&mut (*gl_window), new_gl_window);

        Ok(())
    }

    /// Borrow the inner glutin GlWindow.
    #[inline]
    pub fn gl_window(&self) -> Ref<glutin::GlWindow> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize(w, h);
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

impl fmt::Display for DisplayCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.description())
    }
}

impl Error for DisplayCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => err.description(),
            DisplayCreationError::IncompatibleOpenGl(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<glutin::GlWindow>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<glutin::GlWindow>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        // TODO: 800x600 ?
        let gl_window = self.borrow();
        let (width, height) = gl_window.get_inner_size().unwrap_or((800, 600));
        let scale = gl_window.hidpi_factor();
        ((width as f32 * scale) as u32, (height as f32 * scale) as u32)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        self.borrow().make_current().unwrap();
    }
}
<commit_msg>Rebuild the context when glutin::Display::rebuild is called<commit_after>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use glutin::GlContext;
use std;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<glutin::GlWindow>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<glutin::GlWindow>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new(
        window_builder: glutin::WindowBuilder,
        context_builder: glutin::ContextBuilder,
        events_loop: &glutin::EventsLoop,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = try!(glutin::GlWindow::new(window_builder, context_builder, events_loop));
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window(gl_window: glutin::GlWindow) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked(gl_window: glutin::GlWindow) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug(gl_window: glutin::GlWindow, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug(
        gl_window: glutin::GlWindow,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner(
        gl_window: glutin::GlWindow,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = Rc::new(RefCell::new(gl_window));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = try!(unsafe { context::Context::new(glutin_backend, checked, debug) });
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `GlWindow` with the given window and context builders.
    ///
    /// This method ensures that the new `GlWindow`'s `Context` will share the display lists of the
    /// original `GlWindow`'s `Context`.
    pub fn rebuild(
        &self,
        window_builder: glutin::WindowBuilder,
        context_builder: glutin::ContextBuilder,
        events_loop: &glutin::EventsLoop,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let context_builder = context_builder.with_shared_lists(gl_window.context());
            try!(glutin::GlWindow::new(window_builder, context_builder, events_loop))
        };

        // Replace the stored GlWindow with the new one.
        let mut gl_window = self.gl_window.borrow_mut();
        std::mem::replace(&mut (*gl_window), new_gl_window);

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        try!(unsafe { self.context.rebuild(backend) });

        Ok(())
    }

    /// Borrow the inner glutin GlWindow.
    #[inline]
    pub fn gl_window(&self) -> Ref<glutin::GlWindow> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize(w, h);
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

impl fmt::Display for DisplayCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.description())
    }
}

impl Error for DisplayCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => err.description(),
            DisplayCreationError::IncompatibleOpenGl(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<glutin::GlWindow>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<glutin::GlWindow>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        // TODO: 800x600 ?
        let gl_window = self.borrow();
        let (width, height) = gl_window.get_inner_size().unwrap_or((800, 600));
        let scale = gl_window.hidpi_factor();
        ((width as f32 * scale) as u32, (height as f32 * scale) as u32)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        self.borrow().make_current().unwrap();
    }
}
<|endoftext|>