<commit_before>use crate::task::{self, Poll};
use std::fmt;
use std::marker::{PhantomData,Unpin};
use core::mem::PinMut;

use crate::stream::Stream;

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitrary self types for more
///   information #44874)
pub struct LocalStreamObj<'a, T> {
    ptr: *mut (),
    poll_next_fn: unsafe fn(*mut (), &mut task::Context) -> Poll<Option<T>>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalStreamObj<'a, T> {}

impl<'a, T> LocalStreamObj<'a, T> {
    /// Create a `LocalStreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + 'a>(f: F) -> LocalStreamObj<'a, T> {
        LocalStreamObj {
            ptr: f.into_raw(),
            poll_next_fn: F::poll_next,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalStreamObj` into a `StreamObj`
    /// To make this operation safe one has to ensure that the `UnsafeStreamObj`
    /// instance from which this `LocalStreamObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_stream_obj(self) -> StreamObj<'a, T> {
        StreamObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalStreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalStreamObj")
            .finish()
    }
}

impl<'a, T> From<StreamObj<'a, T>> for LocalStreamObj<'a, T> {
    #[inline]
    fn from(f: StreamObj<'a, T>) -> LocalStreamObj<'a, T> {
        f.0
    }
}

impl<'a, T> Stream for LocalStreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        unsafe {
            (self.poll_next_fn)(self.ptr, cx)
        }
    }
}

impl<'a, T> Drop for LocalStreamObj<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct StreamObj<'a, T>(LocalStreamObj<'a, T>);

impl<'a, T> Unpin for StreamObj<'a, T> {}
unsafe impl<'a, T> Send for StreamObj<'a, T> {}

impl<'a, T> StreamObj<'a, T> {
    /// Create a `StreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + Send>(f: F) -> StreamObj<'a, T> {
        StreamObj(LocalStreamObj::new(f))
    }
}

impl<'a, T> fmt::Debug for StreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("StreamObj")
            .finish()
    }
}

impl<'a, T> Stream for StreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll_next(cx)
    }
}

/// A custom implementation of a future trait object for `StreamObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeStreamObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>>;

    /// Drops the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for &'a mut F
    where F: Stream<Item = T> + Unpin + 'a
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}
<commit_msg>Translate code from src/libcore/mem.rs over to UnsafeStreamObj<commit_after>use crate::task::{self, Poll};
use std::fmt;
use std::marker::{PhantomData,Unpin};
use core::mem::PinMut;

use crate::stream::Stream;

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitrary self types for more
///   information #44874)
pub struct LocalStreamObj<'a, T> {
    ptr: *mut (),
    poll_next_fn: unsafe fn(*mut (), &mut task::Context) -> Poll<Option<T>>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalStreamObj<'a, T> {}

impl<'a, T> LocalStreamObj<'a, T> {
    /// Create a `LocalStreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + 'a>(f: F) -> LocalStreamObj<'a, T> {
        LocalStreamObj {
            ptr: f.into_raw(),
            poll_next_fn: F::poll_next,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalStreamObj` into a `StreamObj`
    /// To make this operation safe one has to ensure that the `UnsafeStreamObj`
    /// instance from which this `LocalStreamObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_stream_obj(self) -> StreamObj<'a, T> {
        StreamObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalStreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalStreamObj")
            .finish()
    }
}

impl<'a, T> From<StreamObj<'a, T>> for LocalStreamObj<'a, T> {
    #[inline]
    fn from(f: StreamObj<'a, T>) -> LocalStreamObj<'a, T> {
        f.0
    }
}

impl<'a, T> Stream for LocalStreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        unsafe {
            (self.poll_next_fn)(self.ptr, cx)
        }
    }
}

impl<'a, T> Drop for LocalStreamObj<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct StreamObj<'a, T>(LocalStreamObj<'a, T>);

impl<'a, T> Unpin for StreamObj<'a, T> {}
unsafe impl<'a, T> Send for StreamObj<'a, T> {}

impl<'a, T> StreamObj<'a, T> {
    /// Create a `StreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + Send>(f: F) -> StreamObj<'a, T> {
        StreamObj(LocalStreamObj::new(f))
    }
}

impl<'a, T> fmt::Debug for StreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("StreamObj")
            .finish()
    }
}

impl<'a, T> Stream for StreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll_next(cx)
    }
}

/// A custom implementation of a future trait object for `StreamObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeStreamObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>>;

    /// Drops the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for &'a mut F
    where F: Stream<Item = T> + Unpin + 'a
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for PinMut<'a, F>
    where F: Stream<Item = T> + 'a
{
    fn into_raw(self) -> *mut () {
        unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}<|endoftext|>


<commit_before>use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt, InferConst};
use crate::mir::interpret::ConstValue;
use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue, UnificationTable};
use rustc_data_structures::unify::InPlace;
use syntax_pos::{Span, DUMMY_SP};
use syntax::symbol::InternedString;

use std::cmp;
use std::marker::PhantomData;
use std::cell::RefMut;

pub trait ToType {
    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
}

impl UnifyKey for ty::IntVid {
    type Value = Option<IntVarValue>;
    fn index(&self) -> u32 { self.index }
    fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
    fn tag() -> &'static str { "IntVid" }
}

impl EqUnifyValue for IntVarValue {}

#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey {
    /// The minimum region vid in the unification set. This is needed
    /// to have a canonical name for a type to prevent infinite
    /// recursion.
    pub min_vid: ty::RegionVid
}

impl UnifyValue for RegionVidKey {
    type Error = NoError;

    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
        let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
            value1.min_vid
        } else {
            value2.min_vid
        };

        Ok(RegionVidKey { min_vid })
    }
}

impl UnifyKey for ty::RegionVid {
    type Value = RegionVidKey;
    fn index(&self) -> u32 { u32::from(*self) }
    fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid::from(i) }
    fn tag() -> &'static str { "RegionVid" }
}

impl ToType for IntVarValue {
    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        match *self {
            ty::IntType(i) => tcx.mk_mach_int(i),
            ty::UintType(i) => tcx.mk_mach_uint(i),
        }
    }
}

// Floating point type keys

impl UnifyKey for ty::FloatVid {
    type Value = Option<FloatVarValue>;
    fn index(&self) -> u32 { self.index }
    fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
    fn tag() -> &'static str { "FloatVid" }
}

impl EqUnifyValue for FloatVarValue {}

impl ToType for FloatVarValue {
    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        tcx.mk_mach_float(self.0)
    }
}

// Generic consts.

/// Reasons to create a const inference variable
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableOrigin {
    MiscVariable(Span),
    ConstInference(Span),
    ConstParameterDefinition(Span, InternedString),
    SubstitutionPlaceholder(Span),
}

#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
    Known { value: &'tcx ty::Const<'tcx> },
    Unknown { universe: ty::UniverseIndex },
}

impl<'tcx> ConstVariableValue<'tcx> {
    /// If this value is known, returns the const it is known to be.
    /// Otherwise, `None`.
    pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> {
        match *self {
            ConstVariableValue::Unknown { .. } => None,
            ConstVariableValue::Known { value } => Some(value),
        }
    }

    pub fn is_unknown(&self) -> bool {
        match *self {
            ConstVariableValue::Unknown { .. } => true,
            ConstVariableValue::Known { .. } => false,
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct ConstVarValue<'tcx> {
    pub origin: ConstVariableOrigin,
    pub val: ConstVariableValue<'tcx>,
}

impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
    type Value = ConstVarValue<'tcx>;
    fn index(&self) -> u32 { self.index }
    fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } }
    fn tag() -> &'static str { "ConstVid" }
}

impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
    type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);

    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
        let val = match (value1.val, value2.val) {
            (
                ConstVariableValue::Known { value: value1 },
                ConstVariableValue::Known { value: value2 }
            ) => {
                match <&'tcx ty::Const<'tcx>>::unify_values(&value1, &value2) {
                    Ok(value) => Ok(ConstVariableValue::Known { value }),
                    Err(err) => Err(err),
                }
            }

            // If one side is known, prefer that one.
            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
                Ok(value1.val)
            }
            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
                Ok(value2.val)
            }

            // If both sides are *unknown*, it hardly matters, does it?
            (ConstVariableValue::Unknown { universe: universe1 },
             ConstVariableValue::Unknown { universe: universe2 }) =>  {
                // If we unify two unbound variables, ?T and ?U, then whatever
                // value they wind up taking (which must be the same value) must
                // be nameable by both universes. Therefore, the resulting
                // universe is the minimum of the two universes, because that is
                // the one which contains the fewest names in scope.
                let universe = cmp::min(universe1, universe2);
                Ok(ConstVariableValue::Unknown { universe })
            }
        }?;

        Ok(ConstVarValue {
            origin: ConstVariableOrigin::ConstInference(DUMMY_SP),
            val,
        })
    }
}

impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}

pub fn replace_if_possible(
    mut table: RefMut<'_, UnificationTable<InPlace<ty::ConstVid<'tcx>>>>,
    c: &'tcx ty::Const<'tcx>
) -> &'tcx ty::Const<'tcx> {
    if let ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } = c {
        match table.probe_value(*vid).val.known() {
            Some(c) => c,
            None => c,
        }
    } else {
        c
    }
}
<commit_msg>Fix known-known const unification case<commit_after>use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt, InferConst};
use crate::mir::interpret::ConstValue;
use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue, UnificationTable};
use rustc_data_structures::unify::InPlace;
use syntax_pos::{Span, DUMMY_SP};
use syntax::symbol::InternedString;

use std::cmp;
use std::marker::PhantomData;
use std::cell::RefMut;

pub trait ToType {
    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
}

impl UnifyKey for ty::IntVid {
    type Value = Option<IntVarValue>;
    fn index(&self) -> u32 { self.index }
    fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
    fn tag() -> &'static str { "IntVid" }
}

impl EqUnifyValue for IntVarValue {}

#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey {
    /// The minimum region vid in the unification set. This is needed
    /// to have a canonical name for a type to prevent infinite
    /// recursion.
    pub min_vid: ty::RegionVid
}

impl UnifyValue for RegionVidKey {
    type Error = NoError;

    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
        let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
            value1.min_vid
        } else {
            value2.min_vid
        };

        Ok(RegionVidKey { min_vid })
    }
}

impl UnifyKey for ty::RegionVid {
    type Value = RegionVidKey;
    fn index(&self) -> u32 { u32::from(*self) }
    fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid::from(i) }
    fn tag() -> &'static str { "RegionVid" }
}

impl ToType for IntVarValue {
    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        match *self {
            ty::IntType(i) => tcx.mk_mach_int(i),
            ty::UintType(i) => tcx.mk_mach_uint(i),
        }
    }
}

// Floating point type keys

impl UnifyKey for ty::FloatVid {
    type Value = Option<FloatVarValue>;
    fn index(&self) -> u32 { self.index }
    fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
    fn tag() -> &'static str { "FloatVid" }
}

impl EqUnifyValue for FloatVarValue {}

impl ToType for FloatVarValue {
    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        tcx.mk_mach_float(self.0)
    }
}

// Generic consts.

/// Reasons to create a const inference variable
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableOrigin {
    MiscVariable(Span),
    ConstInference(Span),
    ConstParameterDefinition(Span, InternedString),
    SubstitutionPlaceholder(Span),
}

#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
    Known { value: &'tcx ty::Const<'tcx> },
    Unknown { universe: ty::UniverseIndex },
}

impl<'tcx> ConstVariableValue<'tcx> {
    /// If this value is known, returns the const it is known to be.
    /// Otherwise, `None`.
    pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> {
        match *self {
            ConstVariableValue::Unknown { .. } => None,
            ConstVariableValue::Known { value } => Some(value),
        }
    }

    pub fn is_unknown(&self) -> bool {
        match *self {
            ConstVariableValue::Unknown { .. } => true,
            ConstVariableValue::Known { .. } => false,
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct ConstVarValue<'tcx> {
    pub origin: ConstVariableOrigin,
    pub val: ConstVariableValue<'tcx>,
}

impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
    type Value = ConstVarValue<'tcx>;
    fn index(&self) -> u32 { self.index }
    fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } }
    fn tag() -> &'static str { "ConstVid" }
}

impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
    type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);

    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
        let val = match (value1.val, value2.val) {
            (
                ConstVariableValue::Known { value: value1 },
                ConstVariableValue::Known { value: value2 }
            ) => {
                bug!("equating two const variables, both of which have known values")
            }

            // If one side is known, prefer that one.
            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
                Ok(value1.val)
            }
            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
                Ok(value2.val)
            }

            // If both sides are *unknown*, it hardly matters, does it?
            (ConstVariableValue::Unknown { universe: universe1 },
             ConstVariableValue::Unknown { universe: universe2 }) =>  {
                // If we unify two unbound variables, ?T and ?U, then whatever
                // value they wind up taking (which must be the same value) must
                // be nameable by both universes. Therefore, the resulting
                // universe is the minimum of the two universes, because that is
                // the one which contains the fewest names in scope.
                let universe = cmp::min(universe1, universe2);
                Ok(ConstVariableValue::Unknown { universe })
            }
        }?;

        Ok(ConstVarValue {
            origin: ConstVariableOrigin::ConstInference(DUMMY_SP),
            val,
        })
    }
}

impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}

pub fn replace_if_possible(
    mut table: RefMut<'_, UnificationTable<InPlace<ty::ConstVid<'tcx>>>>,
    c: &'tcx ty::Const<'tcx>
) -> &'tcx ty::Const<'tcx> {
    if let ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } = c {
        match table.probe_value(*vid).val.known() {
            Some(c) => c,
            None => c,
        }
    } else {
        c
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    use crate::*;

    fn check_raw_str(
        s: &str,
        expected: UnvalidatedRawStr,
        validated: Result<ValidatedRawStr, LexRawStrError>,
    ) {
        let mut cursor = Cursor::new(s);
        let tok = cursor.raw_double_quoted_string(0);
        assert_eq!(tok, expected);
        assert_eq!(tok.validate(), validated);
    }

    #[test]
    fn test_naked_raw_str() {
        check_raw_str(
            r#""abc""#,
            UnvalidatedRawStr {
                n_start_hashes: 0,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Ok(ValidatedRawStr { n_hashes: 0 }),
        );
    }

    #[test]
    fn test_raw_no_start() {
        check_raw_str(
            r##""abc"#"##,
            UnvalidatedRawStr {
                n_start_hashes: 0,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Ok(ValidatedRawStr { n_hashes: 0 }),
        );
    }

    #[test]
    fn test_too_many_terminators() {
        // this error is handled in the parser later
        check_raw_str(
            r###"#"abc"##"###,
            UnvalidatedRawStr {
                n_start_hashes: 1,
                n_end_hashes: 1,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Ok(ValidatedRawStr { n_hashes: 1 }),
        );
    }

    #[test]
    fn test_unterminated() {
        check_raw_str(
            r#"#"abc"#,
            UnvalidatedRawStr {
                n_start_hashes: 1,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Err(LexRawStrError::NoTerminator {
                expected: 1,
                found: 0,
                possible_terminator_offset: None,
            }),
        );
        check_raw_str(
            r###"##"abc"#"###,
            UnvalidatedRawStr {
                n_start_hashes: 2,
                n_end_hashes: 1,
                valid_start: true,
                possible_terminator_offset: Some(7),
            },
            Err(LexRawStrError::NoTerminator {
                expected: 2,
                found: 1,
                possible_terminator_offset: Some(7),
            }),
        );
        // We're looking for "# not just any #
        check_raw_str(
            r###"##"abc#"###,
            UnvalidatedRawStr {
                n_start_hashes: 2,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Err(LexRawStrError::NoTerminator {
                expected: 2,
                found: 0,
                possible_terminator_offset: None,
            }),
        )
    }

    #[test]
    fn test_invalid_start() {
        check_raw_str(
            r##"#~"abc"#"##,
            UnvalidatedRawStr {
                n_start_hashes: 1,
                n_end_hashes: 0,
                valid_start: false,
                possible_terminator_offset: None,
            },
            Err(LexRawStrError::InvalidStarter),
        );
    }
}
<commit_msg>Fix tests to handle debug_assert<commit_after>#[cfg(test)]
mod tests {
    use crate::*;

    fn check_raw_str(
        s: &str,
        expected: UnvalidatedRawStr,
        validated: Result<ValidatedRawStr, LexRawStrError>,
    ) {
        let s = &format!("r{}", s);
        let mut cursor = Cursor::new(s);
        cursor.bump();
        let tok = cursor.raw_double_quoted_string(0);
        assert_eq!(tok, expected);
        assert_eq!(tok.validate(), validated);
    }

    #[test]
    fn test_naked_raw_str() {
        check_raw_str(
            r#""abc""#,
            UnvalidatedRawStr {
                n_start_hashes: 0,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Ok(ValidatedRawStr { n_hashes: 0 }),
        );
    }

    #[test]
    fn test_raw_no_start() {
        check_raw_str(
            r##""abc"#"##,
            UnvalidatedRawStr {
                n_start_hashes: 0,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Ok(ValidatedRawStr { n_hashes: 0 }),
        );
    }

    #[test]
    fn test_too_many_terminators() {
        // this error is handled in the parser later
        check_raw_str(
            r###"#"abc"##"###,
            UnvalidatedRawStr {
                n_start_hashes: 1,
                n_end_hashes: 1,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Ok(ValidatedRawStr { n_hashes: 1 }),
        );
    }

    #[test]
    fn test_unterminated() {
        check_raw_str(
            r#"#"abc"#,
            UnvalidatedRawStr {
                n_start_hashes: 1,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Err(LexRawStrError::NoTerminator {
                expected: 1,
                found: 0,
                possible_terminator_offset: None,
            }),
        );
        check_raw_str(
            r###"##"abc"#"###,
            UnvalidatedRawStr {
                n_start_hashes: 2,
                n_end_hashes: 1,
                valid_start: true,
                possible_terminator_offset: Some(7),
            },
            Err(LexRawStrError::NoTerminator {
                expected: 2,
                found: 1,
                possible_terminator_offset: Some(7),
            }),
        );
        // We're looking for "# not just any #
        check_raw_str(
            r###"##"abc#"###,
            UnvalidatedRawStr {
                n_start_hashes: 2,
                n_end_hashes: 0,
                valid_start: true,
                possible_terminator_offset: None,
            },
            Err(LexRawStrError::NoTerminator {
                expected: 2,
                found: 0,
                possible_terminator_offset: None,
            }),
        )
    }

    #[test]
    fn test_invalid_start() {
        check_raw_str(
            r##"#~"abc"#"##,
            UnvalidatedRawStr {
                n_start_hashes: 1,
                n_end_hashes: 0,
                valid_start: false,
                possible_terminator_offset: None,
            },
            Err(LexRawStrError::InvalidStarter),
        );
    }
}
<|endoftext|>


<commit_before>pub trait ReplyRenderer {
    fn render(&self) -> String;
}

mod text;
mod image;
mod voice;
mod video;
mod music;
mod articles;
mod transfer_customer_service;

pub use self::text::TextReply;
pub use self::image::ImageReply;
pub use self::voice::VoiceReply;
pub use self::video::VideoReply;
pub use self::music::MusicReply;
pub use self::articles::ArticlesReply;
pub use self::transfer_customer_service::TransferCustomerServiceReply;

pub enum Reply {
    TextReply(TextReply),
    ImageReply(ImageReply),
    VoiceReply(VoiceReply),
    VideoReply(VideoReply),
    MusicReply(MusicReply),
    ArticlesReply(ArticlesReply),
    TransferCustomerServiceReply(TransferCustomerServiceReply),
}<commit_msg>Derive Debug and Clone traits for Reply enum<commit_after>pub trait ReplyRenderer {
    fn render(&self) -> String;
}

mod text;
mod image;
mod voice;
mod video;
mod music;
mod articles;
mod transfer_customer_service;

pub use self::text::TextReply;
pub use self::image::ImageReply;
pub use self::voice::VoiceReply;
pub use self::video::VideoReply;
pub use self::music::MusicReply;
pub use self::articles::ArticlesReply;
pub use self::transfer_customer_service::TransferCustomerServiceReply;

#[derive(Debug, Clone)]
pub enum Reply {
    TextReply(TextReply),
    ImageReply(ImageReply),
    VoiceReply(VoiceReply),
    VideoReply(VideoReply),
    MusicReply(MusicReply),
    ArticlesReply(ArticlesReply),
    TransferCustomerServiceReply(TransferCustomerServiceReply),
}
<|endoftext|>


<commit_before>use super::Shape;
use russell_lab::{vec_mat_mul, Matrix, Vector};

const NDIM: usize = 3;
const NPOINT: usize = 8;
const NEDGE: usize = 12;
const NFACE: usize = 6;
const EDGE_NPOINT: usize = 2;
const FACE_NPOINT: usize = 4;

/// Implements a hexahedron with 8 points
///
/// The natural coordinates range from -1 to +1 with the geometry centred @ 0.
///
/// # Local IDs of points
///
/// ```text
///           4________________7
///         ,'|              ,'|
///       ,'  |            ,'  |
///     ,'    |          ,'    |
///   ,'      |        ,'      |
/// 5'===============6'        |
/// |         |      |         |
/// |         |      |         |
/// |         0_____ | ________3
/// |       ,'       |       ,'
/// |     ,'         |     ,'
/// |   ,'           |   ,'
/// | ,'             | ,'
/// 1________________2'
/// ```
///
/// # Local IDs of edges
///
/// ```text
///                     7
///             +----------------+
///           ,'|              ,'|
///       4 ,'  |8          6,'  |
///       ,'    |          ,'    |
///     ,'      |   5    ,'      |11
///   +'===============+'        |
///   |         |      |         |
///   |         |      |  3      |
///   |         .- - - | -  - - -+
///  9|       ,'       |       ,'
///   |    0,'         |10   ,'
///   |   ,'           |   ,' 2
///   | ,'             | ,'
///   +----------------+'
///           1
/// ```
///
/// # Local IDs of faces
///
/// ```text
///           +----------------+
///         ,'|              ,'|
///       ,'  |  ___       ,'  |
///     ,'    |,'5,'  [0],'    |
///   ,'      |~~~     ,'      |
/// +'===============+'  ,'|   |
/// |   ,'|   |      |   |3|   |
/// |   |2|   |      |   |,'   |
/// |   |,'   +- - - | +- - - -+
/// |       ,'       |       ,'
/// |     ,' [1]  ___|     ,'
/// |   ,'      ,'4,'|   ,'
/// | ,'        ~~~  | ,'
/// +----------------+'
/// ```
pub struct Hex8 {
    coords: Vec<Vector>,       // natural coordinates (npoint, ndim)
    interp: Vector,            // interpolation functions @ natural coordinate (npoint)
    deriv: Matrix,             // derivatives of interpolation functions w.r.t natural coordinate (npoint, ndim)
    edge_ids: Vec<Vec<usize>>, // ids of points on edges
    face_ids: Vec<Vec<usize>>, // ids of points on faces
}

impl Hex8 {
    /// Creates a new object with pre-calculated interpolation fn and derivatives
    pub fn new() -> Self {
        Hex8 {
            #[rustfmt::skip]
            coords: vec![
                Vector::from(&[-1.0, -1.0, -1.0]),
                Vector::from(&[ 1.0, -1.0, -1.0]),
                Vector::from(&[ 1.0,  1.0, -1.0]),
                Vector::from(&[-1.0,  1.0, -1.0]),
                Vector::from(&[-1.0, -1.0,  1.0]),
                Vector::from(&[ 1.0, -1.0,  1.0]),
                Vector::from(&[ 1.0,  1.0,  1.0]),
                Vector::from(&[-1.0,  1.0,  1.0]),
            ],
            interp: Vector::new(NPOINT),
            deriv: Matrix::new(NPOINT, NDIM),
            edge_ids: vec![
                vec![0, 1],
                vec![1, 2],
                vec![2, 3],
                vec![3, 0],
                vec![4, 5],
                vec![5, 6],
                vec![6, 7],
                vec![7, 4],
                vec![0, 4],
                vec![1, 5],
                vec![2, 6],
                vec![3, 7],
            ],
            face_ids: vec![
                vec![0, 4, 7, 3],
                vec![1, 2, 6, 5],
                vec![0, 1, 5, 4],
                vec![2, 3, 7, 6],
                vec![0, 3, 2, 1],
                vec![4, 5, 6, 7],
            ],
        }
    }
}

impl Shape for Hex8 {
    fn calc_interp(&mut self, ksi: &Vector) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        self.interp[0] = (1.0 - r - s + r * s - t + s * t + r * t - r * s * t) / 8.0;
        self.interp[1] = (1.0 + r - s - r * s - t + s * t - r * t + r * s * t) / 8.0;
        self.interp[2] = (1.0 + r + s + r * s - t - s * t - r * t - r * s * t) / 8.0;
        self.interp[3] = (1.0 - r + s - r * s - t - s * t + r * t + r * s * t) / 8.0;
        self.interp[4] = (1.0 - r - s + r * s + t - s * t - r * t + r * s * t) / 8.0;
        self.interp[5] = (1.0 + r - s - r * s + t - s * t + r * t - r * s * t) / 8.0;
        self.interp[6] = (1.0 + r + s + r * s + t + s * t + r * t + r * s * t) / 8.0;
        self.interp[7] = (1.0 - r + s - r * s + t + s * t - r * t - r * s * t) / 8.0;
    }

    fn calc_deriv(&mut self, ksi: &Vector) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        self.deriv[0][0] = (-1.0 + s + t - s * t) / 8.0;
        self.deriv[0][1] = (-1.0 + r + t - r * t) / 8.0;
        self.deriv[0][2] = (-1.0 + r + s - r * s) / 8.0;

        self.deriv[1][0] = (1.0 - s - t + s * t) / 8.0;
        self.deriv[1][1] = (-1.0 - r + t + r * t) / 8.0;
        self.deriv[1][2] = (-1.0 - r + s + r * s) / 8.0;

        self.deriv[2][0] = (1.0 + s - t - s * t) / 8.0;
        self.deriv[2][1] = (1.0 + r - t - r * t) / 8.0;
        self.deriv[2][2] = (-1.0 - r - s - r * s) / 8.0;

        self.deriv[3][0] = (-1.0 - s + t + s * t) / 8.0;
        self.deriv[3][1] = (1.0 - r - t + r * t) / 8.0;
        self.deriv[3][2] = (-1.0 + r - s + r * s) / 8.0;

        self.deriv[4][0] = (-1.0 + s - t + s * t) / 8.0;
        self.deriv[4][1] = (-1.0 + r - t + r * t) / 8.0;
        self.deriv[4][2] = (1.0 - r - s + r * s) / 8.0;

        self.deriv[5][0] = (1.0 - s + t - s * t) / 8.0;
        self.deriv[5][1] = (-1.0 - r - t - r * t) / 8.0;
        self.deriv[5][2] = (1.0 + r - s - r * s) / 8.0;

        self.deriv[6][0] = (1.0 + s + t + s * t) / 8.0;
        self.deriv[6][1] = (1.0 + r + t + r * t) / 8.0;
        self.deriv[6][2] = (1.0 + r + s + r * s) / 8.0;

        self.deriv[7][0] = (-1.0 - s - t - s * t) / 8.0;
        self.deriv[7][1] = (1.0 - r + t - r * t) / 8.0;
        self.deriv[7][2] = (1.0 - r + s - r * s) / 8.0;
    }

    fn get_interp(&self, m: usize) -> f64 {
        self.interp[m]
    }

    fn get_deriv(&self, deriv: &mut Vector, m: usize) {
        deriv[0] = self.deriv[m][0];
        deriv[1] = self.deriv[m][1];
        deriv[2] = self.deriv[m][2];
    }

    fn get_ndim(&self) -> usize {
        NDIM
    }

    fn get_npoint(&self) -> usize {
        NPOINT
    }

    fn get_nedge(&self) -> usize {
        NEDGE
    }

    fn get_nface(&self) -> usize {
        NFACE
    }

    fn get_edge_npoint(&self) -> usize {
        EDGE_NPOINT
    }

    fn get_face_npoint(&self) -> usize {
        FACE_NPOINT
    }

    fn get_edge_local_point_id(&self, e: usize, i: usize) -> usize {
        self.edge_ids[e][i]
    }

    fn get_face_local_point_id(&self, f: usize, i: usize) -> usize {
        self.face_ids[f][i]
    }

    fn get_ksi(&self, ksi: &mut Vector, m: usize) {
        ksi[0] = self.coords[m][0];
        ksi[1] = self.coords[m][1];
        ksi[2] = self.coords[m][2];
    }

    fn mul_interp_by_matrix(&self, v: &mut Vector, a: &Matrix) -> Result<(), &'static str> {
        vec_mat_mul(v, 1.0, &self.interp, a)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn new_works() {
        let geo = Hex8::new();
        assert_eq!(geo.coords.len(), NPOINT);
        assert_eq!(geo.interp.dim(), NPOINT);
        assert_eq!(geo.deriv.dims(), (NPOINT, NDIM));
    }
}
<commit_msg>Improve Hex8<commit_after>use super::Shape;
use russell_lab::{vec_mat_mul, Matrix, Vector};

const NDIM: usize = 3;
const NPOINT: usize = 8;
const NEDGE: usize = 12;
const NFACE: usize = 6;
const EDGE_NPOINT: usize = 2;
const FACE_NPOINT: usize = 4;
const FACE_NEDGE: usize = 4;

#[rustfmt::skip]
const EDGE_POINT_IDS: [[usize; 2]; 12] = [
    [0, 1],
    [1, 2],
    [2, 3],
    [3, 0],
    [4, 5],
    [5, 6],
    [6, 7],
    [7, 4],
    [0, 4],
    [1, 5],
    [2, 6],
    [3, 7],
];

#[rustfmt::skip]
const FACE_POINT_IDS: [[usize; 4]; 6] = [
    [0, 4, 7, 3],
    [1, 2, 6, 5],
    [0, 1, 5, 4],
    [2, 3, 7, 6],
    [0, 3, 2, 1],
    [4, 5, 6, 7],
];

#[rustfmt::skip]
const FACE_EDGE_POINT_IDS: [[[usize; 2]; 4]; 6] = [
    [[0, 4], [4, 7], [7, 3], [3, 0]],
    [[1, 2], [2, 6], [6, 5], [5, 1]],
    [[0, 1], [1, 5], [5, 4], [4, 0]],
    [[2, 3], [3, 7], [7, 6], [6, 2]],
    [[0, 3], [3, 2], [2, 1], [1, 0]],
    [[4, 5], [5, 6], [6, 7], [7, 4]],
];

#[rustfmt::skip]
const POINT_NATURAL_COORDS: [[f64; 3]; 8] = [
    [-1.0, -1.0, -1.0],
    [ 1.0, -1.0, -1.0],
    [ 1.0,  1.0, -1.0],
    [-1.0,  1.0, -1.0],
    [-1.0, -1.0,  1.0],
    [ 1.0, -1.0,  1.0],
    [ 1.0,  1.0,  1.0],
    [-1.0,  1.0,  1.0],
];

/// Implements a hexahedron with 8 points
///
/// The natural coordinates range from -1 to +1 with the geometry centred @ 0.
///
/// # Local IDs of points
///
/// ```text
///           4________________7
///         ,'|              ,'|
///       ,'  |            ,'  |             r     s     t
///     ,'    |          ,'    |     p:0 [-1.0, -1.0, -1.0]
///   ,'      |        ,'      |     p:1 [ 1.0, -1.0, -1.0]
/// 5'===============6'        |     p:2 [ 1.0,  1.0, -1.0]
/// |         |      |         |     p:3 [-1.0,  1.0, -1.0]
/// |         |      |         |     p:4 [-1.0, -1.0,  1.0]
/// |         0_____ | ________3     p:5 [ 1.0, -1.0,  1.0]
/// |       ,'       |       ,'      p:6 [ 1.0,  1.0,  1.0]
/// |     ,'         |     ,'        p:7 [-1.0,  1.0,  1.0]
/// |   ,'           |   ,'
/// | ,'             | ,'
/// 1________________2'
/// ```
///
/// # Local IDs of edges
///
/// ```text
///                     7                   p0  p1
///             +----------------+     e:0  [0, 1]
///           ,'|              ,'|     e:1  [1, 2]
///       4 ,'  |8          6,'  |     e:2  [2, 3]
///       ,'    |          ,'    |     e:3  [3, 0]
///     ,'      |   5    ,'      |11   e:4  [4, 5]
///   +'===============+'        |     e:5  [5, 6]
///   |         |      |         |     e:6  [6, 7]
///   |         |      |  3      |     e:7  [7, 4]
///   |         .- - - | -  - - -+     e:8  [0, 4]
///  9|       ,'       |       ,'      e:9  [1, 5]
///   |    0,'         |10   ,'        e:10 [2, 6]
///   |   ,'           |   ,' 2        e:11 [3, 7]
///   | ,'             | ,'
///   +----------------+'
///           1
/// ```
///
/// # Local IDs of faces
///
/// Note: the order of points is such that the right-hand rule generates outward normals.
///
/// ```text
///           4----------------7
///         ,'|              ,'|
///       ,'  |  ___       ,'  |
///     ,'    |,'5,'  [0],'    |        p0 p1 p2 p3
///   ,'      |~~~     ,'      |    f:0 [0, 4, 7, 3]
/// 5'===============6'  ,'|   |    f:1 [1, 2, 6, 5]
/// |   ,'|   |      |   |3|   |    f:2 [0, 1, 5, 4]
/// |   |2|   |      |   |,'   |    f:3 [2, 3, 7, 6]
/// |   |,'   0- - - | +- - - -3    f:4 [0, 3, 2, 1]
/// |       ,'       |       ,'     f:5 [4, 5, 6, 7]
/// |     ,' [1]  ___|     ,'
/// |   ,'      ,'4,'|   ,'
/// | ,'        ~~~  | ,'
/// 1----------------2'
/// ```
pub struct Hex8 {
    interp: Vector, // interpolation functions @ natural coordinate (npoint)
    deriv: Matrix,  // derivatives of interpolation functions w.r.t natural coordinate (npoint, ndim)
}

impl Hex8 {
    /// Creates a new object with pre-calculated interpolation fn and derivatives
    pub fn new() -> Self {
        Hex8 {
            interp: Vector::new(NPOINT),
            deriv: Matrix::new(NPOINT, NDIM),
        }
    }
}

impl Shape for Hex8 {
    fn calc_interp(&mut self, ksi: &Vector) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        self.interp[0] = (1.0 - r - s + r * s - t + s * t + r * t - r * s * t) / 8.0;
        self.interp[1] = (1.0 + r - s - r * s - t + s * t - r * t + r * s * t) / 8.0;
        self.interp[2] = (1.0 + r + s + r * s - t - s * t - r * t - r * s * t) / 8.0;
        self.interp[3] = (1.0 - r + s - r * s - t - s * t + r * t + r * s * t) / 8.0;
        self.interp[4] = (1.0 - r - s + r * s + t - s * t - r * t + r * s * t) / 8.0;
        self.interp[5] = (1.0 + r - s - r * s + t - s * t + r * t - r * s * t) / 8.0;
        self.interp[6] = (1.0 + r + s + r * s + t + s * t + r * t + r * s * t) / 8.0;
        self.interp[7] = (1.0 - r + s - r * s + t + s * t - r * t - r * s * t) / 8.0;
    }

    fn calc_deriv(&mut self, ksi: &Vector) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        self.deriv[0][0] = (-1.0 + s + t - s * t) / 8.0;
        self.deriv[0][1] = (-1.0 + r + t - r * t) / 8.0;
        self.deriv[0][2] = (-1.0 + r + s - r * s) / 8.0;

        self.deriv[1][0] = (1.0 - s - t + s * t) / 8.0;
        self.deriv[1][1] = (-1.0 - r + t + r * t) / 8.0;
        self.deriv[1][2] = (-1.0 - r + s + r * s) / 8.0;

        self.deriv[2][0] = (1.0 + s - t - s * t) / 8.0;
        self.deriv[2][1] = (1.0 + r - t - r * t) / 8.0;
        self.deriv[2][2] = (-1.0 - r - s - r * s) / 8.0;

        self.deriv[3][0] = (-1.0 - s + t + s * t) / 8.0;
        self.deriv[3][1] = (1.0 - r - t + r * t) / 8.0;
        self.deriv[3][2] = (-1.0 + r - s + r * s) / 8.0;

        self.deriv[4][0] = (-1.0 + s - t + s * t) / 8.0;
        self.deriv[4][1] = (-1.0 + r - t + r * t) / 8.0;
        self.deriv[4][2] = (1.0 - r - s + r * s) / 8.0;

        self.deriv[5][0] = (1.0 - s + t - s * t) / 8.0;
        self.deriv[5][1] = (-1.0 - r - t - r * t) / 8.0;
        self.deriv[5][2] = (1.0 + r - s - r * s) / 8.0;

        self.deriv[6][0] = (1.0 + s + t + s * t) / 8.0;
        self.deriv[6][1] = (1.0 + r + t + r * t) / 8.0;
        self.deriv[6][2] = (1.0 + r + s + r * s) / 8.0;

        self.deriv[7][0] = (-1.0 - s - t - s * t) / 8.0;
        self.deriv[7][1] = (1.0 - r + t - r * t) / 8.0;
        self.deriv[7][2] = (1.0 - r + s - r * s) / 8.0;
    }

    fn get_interp(&self, m: usize) -> f64 {
        self.interp[m]
    }

    fn get_deriv(&self, deriv: &mut Vector, m: usize) {
        deriv[0] = self.deriv[m][0];
        deriv[1] = self.deriv[m][1];
        deriv[2] = self.deriv[m][2];
    }

    fn get_ndim(&self) -> usize {
        NDIM
    }

    fn get_npoint(&self) -> usize {
        NPOINT
    }

    fn get_nedge(&self) -> usize {
        NEDGE
    }

    fn get_nface(&self) -> usize {
        NFACE
    }

    fn get_edge_npoint(&self) -> usize {
        EDGE_NPOINT
    }

    fn get_face_npoint(&self) -> usize {
        FACE_NPOINT
    }

    fn get_face_nedge(&self) -> usize {
        FACE_NEDGE
    }

    fn get_edge_local_point_id(&self, e: usize, i: usize) -> usize {
        EDGE_POINT_IDS[e][i]
    }

    fn get_face_local_point_id(&self, f: usize, i: usize) -> usize {
        FACE_POINT_IDS[f][i]
    }

    fn get_face_edge_local_point_id(&self, f: usize, k: usize, i: usize) -> usize {
        FACE_EDGE_POINT_IDS[f][k][i]
    }

    fn get_ksi(&self, ksi: &mut Vector, m: usize) {
        ksi[0] = POINT_NATURAL_COORDS[m][0];
        ksi[1] = POINT_NATURAL_COORDS[m][1];
        ksi[2] = POINT_NATURAL_COORDS[m][2];
    }

    fn mul_interp_by_matrix(&self, v: &mut Vector, a: &Matrix) -> Result<(), &'static str> {
        vec_mat_mul(v, 1.0, &self.interp, a)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn new_works() {
        let shape = Hex8::new();
        assert_eq!(shape.interp.dim(), NPOINT);
        assert_eq!(shape.deriv.dims(), (NPOINT, NDIM));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{
    agent_error::ImlAgentError,
    daemon_plugins::{DaemonPlugin, Output},
    env,
    http_comms::mailbox_client::send,
};
use async_trait::async_trait;
use futures::{
    executor::block_on,
    stream::{StreamExt as _, TryStreamExt},
    Future, FutureExt,
};
use inotify::{Inotify, WatchMask};
use std::{
    collections::{HashMap, HashSet},
    pin::Pin,
    sync::Arc,
};
use stream_cancel::{Trigger, Tripwire};
use tokio::{fs, net::UnixListener, sync::Mutex};
use tokio_util::codec::{BytesCodec, FramedRead};

pub struct PostOffice {
    // individual mailbox socket listeners
    routes: Arc<Mutex<HashMap<String, Trigger>>>,
    trigger: Option<Trigger>,
}

pub fn create() -> impl DaemonPlugin {
    PostOffice {
        routes: Arc::new(Mutex::new(HashMap::new())),
        trigger: None,
    }
}

/// Return socket address for a given mailbox
pub fn socket_name(mailbox: &str) -> String {
    let sock_dir = env::get_var("SOCK_DIR");
    format!("{}/postman-{}.sock", sock_dir, mailbox)
}

impl std::fmt::Debug for PostOffice {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "PostOffice {{ {:?} }}",
            block_on(self.routes.lock()).keys()
        )
    }
}

// Returned trigger should be dropped to cause route to stop
fn start_route(mailbox: String) -> Trigger {
    let (trigger, tripwire) = Tripwire::new();
    let addr = socket_name(&mailbox);

    let rc = async move {
        // remove old unix socket
        let _ = fs::remove_file(&addr).await.map_err(|e| {
            tracing::debug!("Failed to remove file {}: {}", &addr, &e);
        });
        let mut listener = UnixListener::bind(addr.clone()).map_err(|e| {
            tracing::error!("Failed to open unix socket {}: {}", &addr, &e);
            e
        })?;
        let mut incoming = listener.incoming().take_until(tripwire);

        tracing::debug!("Starting Route for {}", mailbox);
        while let Some(inbound) = incoming.next().await {
            match inbound {
                Ok(inbound) => {
                    let stream = FramedRead::new(inbound, BytesCodec::new())
                        .map_ok(bytes::BytesMut::freeze)
                        .err_into();
                    let transfer = send(mailbox.clone(), stream).map(|r| {
                        if let Err(e) = r {
                            tracing::error!("Failed to transfer: {}", e);
                        }
                    });
                    tokio::spawn(transfer);
                }
                Err(e) => tracing::error!("Failed transfer: {}", e),
            }
        }
        tracing::debug!("Ending Route for {}", mailbox);
        fs::remove_file(&addr).await.map_err(|e| {
            tracing::error!("Failed to remove socket {}: {}", &addr, &e);
            e
        })
    };
    tokio::spawn(rc);
    trigger
}

#[async_trait]
impl DaemonPlugin for PostOffice {
    fn start_session(
        &mut self,
    ) -> Pin<Box<dyn Future<Output = Result<Output, ImlAgentError>> + Send>> {
        let routes = Arc::clone(&self.routes);
        let mut inotify = Inotify::init().expect("Failed to initialize inotify");
        let conf_file = env::get_var("POSTMAN_CONF_PATH");

        let (trigger, tripwire) = Tripwire::new();

        self.trigger = Some(trigger);

        async move {
            if let Ok(file) = fs::read_to_string(&conf_file).await {
                let itr = file.lines().map(|mb| {
                    let trigger = start_route(mb.to_string());
                    (mb.to_string(), trigger)
                });
                routes.lock().await.extend(itr);
            } else {
                fs::OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(&conf_file)
                    .await?;
            }

            inotify
                .add_watch(&conf_file, WatchMask::MODIFY)
                .map_err(|e| tracing::error!("Failed to watch configuration: {}", e))
                .ok();

            let watcher = async move {
                let mut buffer = [0; 32];
                let stream = inotify.event_stream(&mut buffer)?;
                let mut events = stream.take_until(tripwire);

                while let Some(ev) = events.next().await {
                    tracing::debug!("inotify event: {:?}", ev);
                    match fs::read_to_string(&conf_file).await {
                        Ok(file) => {
                            let newset: HashSet<String> =
                                file.lines().map(|s| s.to_string()).collect();
                            let oldset: HashSet<String> =
                                routes.lock().await.keys().cloned().collect();

                            let added = &newset - &oldset;
                            let itr = added.iter().map(|mb| {
                                let trigger = start_route(mb.to_string());
                                (mb.to_string(), trigger)
                            });
                            let mut rt = routes.lock().await;
                            rt.extend(itr);
                            for rm in &oldset - &newset {
                                rt.remove(&rm);
                            }
                        }
                        Err(e) => {
                            tracing::error!("Failed to open configuration {}: {}", &conf_file, e)
                        }
                    };
                }
                tracing::debug!("Ending Inotify Listen for {}", &conf_file);
                Ok::<_, ImlAgentError>(())
            };

            tokio::spawn(watcher);
            Ok(None)
        }
        .boxed()
    }

    async fn teardown(&mut self) -> Result<(), ImlAgentError> {
        // drop all triggers
        self.routes.lock().await.clear();
        self.trigger.take();
        Ok(())
    }
}
<commit_msg>Remove blocking debug in postoffice (#2002)<commit_after>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{
    agent_error::ImlAgentError,
    daemon_plugins::{DaemonPlugin, Output},
    env,
    http_comms::mailbox_client::send,
};
use async_trait::async_trait;
use futures::{
    stream::{StreamExt as _, TryStreamExt},
    Future, FutureExt,
};
use inotify::{Inotify, WatchMask};
use std::{
    collections::{HashMap, HashSet},
    pin::Pin,
    sync::Arc,
};
use stream_cancel::{Trigger, Tripwire};
use tokio::{fs, net::UnixListener, sync::Mutex};
use tokio_util::codec::{BytesCodec, FramedRead};

pub struct PostOffice {
    // individual mailbox socket listeners
    routes: Arc<Mutex<HashMap<String, Trigger>>>,
    trigger: Option<Trigger>,
}

pub fn create() -> impl DaemonPlugin {
    PostOffice {
        routes: Arc::new(Mutex::new(HashMap::new())),
        trigger: None,
    }
}

/// Return socket address for a given mailbox
pub fn socket_name(mailbox: &str) -> String {
    let sock_dir = env::get_var("SOCK_DIR");
    format!("{}/postman-{}.sock", sock_dir, mailbox)
}

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

// Returned trigger should be dropped to cause route to stop
fn start_route(mailbox: String) -> Trigger {
    let (trigger, tripwire) = Tripwire::new();
    let addr = socket_name(&mailbox);

    let rc = async move {
        // remove old unix socket
        let _ = fs::remove_file(&addr).await.map_err(|e| {
            tracing::debug!("Failed to remove file {}: {}", &addr, &e);
        });
        let mut listener = UnixListener::bind(addr.clone()).map_err(|e| {
            tracing::error!("Failed to open unix socket {}: {}", &addr, &e);
            e
        })?;
        let mut incoming = listener.incoming().take_until(tripwire);

        tracing::debug!("Starting Route for {}", mailbox);
        while let Some(inbound) = incoming.next().await {
            match inbound {
                Ok(inbound) => {
                    let stream = FramedRead::new(inbound, BytesCodec::new())
                        .map_ok(bytes::BytesMut::freeze)
                        .err_into();
                    let transfer = send(mailbox.clone(), stream).map(|r| {
                        if let Err(e) = r {
                            tracing::error!("Failed to transfer: {}", e);
                        }
                    });
                    tokio::spawn(transfer);
                }
                Err(e) => tracing::error!("Failed transfer: {}", e),
            }
        }
        tracing::debug!("Ending Route for {}", mailbox);
        fs::remove_file(&addr).await.map_err(|e| {
            tracing::error!("Failed to remove socket {}: {}", &addr, &e);
            e
        })
    };
    tokio::spawn(rc);
    trigger
}

#[async_trait]
impl DaemonPlugin for PostOffice {
    fn start_session(
        &mut self,
    ) -> Pin<Box<dyn Future<Output = Result<Output, ImlAgentError>> + Send>> {
        let routes = Arc::clone(&self.routes);
        let mut inotify = Inotify::init().expect("Failed to initialize inotify");
        let conf_file = env::get_var("POSTMAN_CONF_PATH");

        let (trigger, tripwire) = Tripwire::new();

        self.trigger = Some(trigger);

        async move {
            if let Ok(file) = fs::read_to_string(&conf_file).await {
                let itr = file.lines().map(|mb| {
                    let trigger = start_route(mb.to_string());
                    (mb.to_string(), trigger)
                });
                routes.lock().await.extend(itr);
            } else {
                fs::OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(&conf_file)
                    .await?;
            }

            inotify
                .add_watch(&conf_file, WatchMask::MODIFY)
                .map_err(|e| tracing::error!("Failed to watch configuration: {}", e))
                .ok();

            let watcher = async move {
                let mut buffer = [0; 32];
                let stream = inotify.event_stream(&mut buffer)?;
                let mut events = stream.take_until(tripwire);

                while let Some(ev) = events.next().await {
                    tracing::debug!("inotify event: {:?}", ev);
                    match fs::read_to_string(&conf_file).await {
                        Ok(file) => {
                            let newset: HashSet<String> =
                                file.lines().map(|s| s.to_string()).collect();
                            let oldset: HashSet<String> =
                                routes.lock().await.keys().cloned().collect();

                            let added = &newset - &oldset;
                            let itr = added.iter().map(|mb| {
                                let trigger = start_route(mb.to_string());
                                (mb.to_string(), trigger)
                            });
                            let mut rt = routes.lock().await;
                            rt.extend(itr);
                            for rm in &oldset - &newset {
                                rt.remove(&rm);
                            }
                        }
                        Err(e) => {
                            tracing::error!("Failed to open configuration {}: {}", &conf_file, e)
                        }
                    };
                }
                tracing::debug!("Ending Inotify Listen for {}", &conf_file);
                Ok::<_, ImlAgentError>(())
            };

            tokio::spawn(watcher);
            Ok(None)
        }
        .boxed()
    }

    async fn teardown(&mut self) -> Result<(), ImlAgentError> {
        // drop all triggers
        self.routes.lock().await.clear();
        self.trigger.take();
        Ok(())
    }
}
<|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 std::collections::HashSet;
use std::io::ErrorKind;
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::{fs, str};

use stratis::StratisResult;

use super::super::engine::Pool;
use super::types::{Name, PoolUuid};

use super::engine::DEV_PATH;

/// Set up the root Stratis directory, where dev links as well as temporary
/// MDV mounts will be created. This must occur before any pools are setup.
pub fn setup_dev_path() -> StratisResult<()> {
    if let Err(err) = fs::create_dir(DEV_PATH) {
        if err.kind() != ErrorKind::AlreadyExists {
            return Err(From::from(err));
        }
    }

    Ok(())
}

/// Set up directories and symlinks under /dev/stratis based on current
/// config. Clear out any directory or file that doesn't correspond to a pool
/// or filesystem.
// Don't just remove and recreate everything in case there are processes
// (e.g. user shells) with the current working directory within the tree.
pub fn setup_devlinks<'a, I: Iterator<Item = &'a (Name, PoolUuid, &'a Pool)>>(pools: I) -> () {
    match || -> StratisResult<()> {
        let mut existing_dirs = fs::read_dir(DEV_PATH)?
            .map(|dir_e| {
                dir_e.and_then(|d| Ok(d.file_name().into_string().expect("Unix is utf-8")))
            })
            .collect::<Result<HashSet<_>, _>>()?;

        for &(ref pool_name, _, pool) in pools {
            if !existing_dirs.remove(&pool_name.to_owned()) {
                pool_added(pool_name);
            }

            let pool_path = pool_directory(pool_name);

            let mut existing_files = fs::read_dir(pool_path)?
                .map(|dir_e| {
                    dir_e.and_then(|d| Ok(d.file_name().into_string().expect("Unix is utf-8")))
                })
                .collect::<Result<HashSet<_>, _>>()?;

            for (fs_name, _, fs) in pool.filesystems() {
                filesystem_added(pool_name, &fs_name, &fs.devnode());
                existing_files.remove(&fs_name.to_owned());
            }

            for leftover in existing_files {
                filesystem_removed(pool_name, &leftover);
            }
        }

        for leftover in existing_dirs {
            pool_removed(&Name::new(leftover));
        }

        Ok(())
    }() {
        Err(e) => {
            warn!("setup_devlinks failed, reason {:?}", e);
            ()
        }
        Ok(_) => (),
    };
}

/// Create a directory when a pool is added.
pub fn pool_added(pool: &str) -> () {
    let p = pool_directory(pool);
    if let Err(e) = fs::create_dir(&p) {
        warn!("unable to create pool directory {:?}, reason {:?}", p, e);
    }
}

/// Remove the directory and its contents when the pool is removed.
pub fn pool_removed(pool: &str) -> () {
    let p = pool_directory(pool);
    if let Err(e) = fs::remove_dir_all(&p) {
        warn!("unable to remove pool directory {:?}, reason {:?}", p, e);
    }
}

/// Rename the directory to match the pool's new name.
pub fn pool_renamed(old_name: &str, new_name: &str) -> () {
    let old = pool_directory(old_name);
    let new = pool_directory(new_name);
    if let Err(e) = fs::rename(&old, &new) {
        warn!(
            "unable to rename pool directory old {:?}, new {:?}, reason {:?}",
            old, new, e
        );
    }
}

/// Create a symlink to the new filesystem's block device within its pool's
/// directory.
pub fn filesystem_added(pool_name: &str, fs_name: &str, devnode: &Path) -> () {
    let p = filesystem_mount_path(pool_name, fs_name);

    // Remove existing and recreate to ensure it points to the correct devnode
    let _ = fs::remove_file(&p);
    if let Err(e) = symlink(devnode, &p) {
        warn!(
            "unable to create symlink for {:?} -> {:?}, reason {:?}",
            devnode, p, e
        );
    }
}

/// Remove the symlink when the filesystem is destroyed.
pub fn filesystem_removed(pool_name: &str, fs_name: &str) -> () {
    let p = filesystem_mount_path(pool_name, fs_name);
    if let Err(e) = fs::remove_file(&p) {
        warn!(
            "unable to remove symlink for filesystem {:?}, reason {:?}",
            p, e
        );
    }
}

/// Rename the symlink to track the filesystem's new name.
pub fn filesystem_renamed(pool_name: &str, old_name: &str, new_name: &str) -> () {
    let old = filesystem_mount_path(pool_name, old_name);
    let new = filesystem_mount_path(pool_name, new_name);
    if let Err(e) = fs::rename(&old, &new) {
        warn!(
            "unable to rename filesystem symlink for {:?} -> {:?}, reason {:?}",
            old, new, e
        );
    }
}

/// Given a pool name, synthesize a pool directory name for storing filesystem
/// mount paths.
fn pool_directory<T: AsRef<str>>(pool_name: T) -> PathBuf {
    vec![DEV_PATH, pool_name.as_ref()].iter().collect()
}

/// Given a pool name and a filesystem name, return the path it should be
/// available as a device for mounting.
pub fn filesystem_mount_path<T: AsRef<str>>(pool_name: T, fs_name: T) -> PathBuf {
    vec![DEV_PATH, pool_name.as_ref(), fs_name.as_ref()]
        .iter()
        .collect()
}
<commit_msg>devlinks: Add setup_pool_devlinks function<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 std::collections::HashSet;
use std::io::ErrorKind;
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::{fs, str};

use stratis::StratisResult;

use super::super::engine::Pool;
use super::types::{Name, PoolUuid};

use super::engine::DEV_PATH;

/// Set up the root Stratis directory, where dev links as well as temporary
/// MDV mounts will be created. This must occur before any pools are setup.
pub fn setup_dev_path() -> StratisResult<()> {
    if let Err(err) = fs::create_dir(DEV_PATH) {
        if err.kind() != ErrorKind::AlreadyExists {
            return Err(From::from(err));
        }
    }

    Ok(())
}

/// Setup the pool directory and the symlinks in /dev/stratis for the specified pool and filesystems
/// it contains.
// Don't just remove and recreate everything in case there are processes
// (e.g. user shells) with the current working directory within the tree.
pub fn setup_pool_devlinks(pool_name: &str, pool: &Pool) -> () {
    match || -> StratisResult<()> {
        let pool_path = pool_directory(pool_name);

        if !pool_path.exists() {
            pool_added(pool_name);
        }

        let mut existing_files = fs::read_dir(pool_path)?
            .map(|dir_e| {
                dir_e.and_then(|d| Ok(d.file_name().into_string().expect("Unix is utf-8")))
            })
            .collect::<Result<HashSet<_>, _>>()?;

        for (fs_name, _, fs) in pool.filesystems() {
            filesystem_added(pool_name, &fs_name, &fs.devnode());
            existing_files.remove(&fs_name.to_owned());
        }

        for leftover in existing_files {
            filesystem_removed(pool_name, &leftover);
        }

        Ok(())
    }() {
        Err(e) => {
            warn!(
                "setup_pool_devlinks failed for /dev/stratis/{}, reason {:?}",
                pool_name, e
            );
            ()
        }
        Ok(_) => (),
    };
}

/// Set up directories and symlinks under /dev/stratis based on current
/// config. Clear out any directory or file that doesn't correspond to a pool
/// or filesystem.
// Don't just remove and recreate everything in case there are processes
// (e.g. user shells) with the current working directory within the tree.
pub fn setup_devlinks<'a, I: Iterator<Item = &'a (Name, PoolUuid, &'a Pool)>>(pools: I) -> () {
    match || -> StratisResult<()> {
        let mut existing_dirs = fs::read_dir(DEV_PATH)?
            .map(|dir_e| {
                dir_e.and_then(|d| Ok(d.file_name().into_string().expect("Unix is utf-8")))
            })
            .collect::<Result<HashSet<_>, _>>()?;

        for &(ref pool_name, _, pool) in pools {
            existing_dirs.remove(&pool_name.to_owned());
            setup_pool_devlinks(&pool_name, pool);
        }

        for leftover in existing_dirs {
            pool_removed(&Name::new(leftover));
        }

        Ok(())
    }() {
        Err(e) => {
            warn!("setup_devlinks failed, reason {:?}", e);
            ()
        }
        Ok(_) => (),
    };
}

/// Create a directory when a pool is added.
pub fn pool_added(pool: &str) -> () {
    let p = pool_directory(pool);
    if let Err(e) = fs::create_dir(&p) {
        warn!("unable to create pool directory {:?}, reason {:?}", p, e);
    }
}

/// Remove the directory and its contents when the pool is removed.
pub fn pool_removed(pool: &str) -> () {
    let p = pool_directory(pool);
    if let Err(e) = fs::remove_dir_all(&p) {
        warn!("unable to remove pool directory {:?}, reason {:?}", p, e);
    }
}

/// Rename the directory to match the pool's new name.
pub fn pool_renamed(old_name: &str, new_name: &str) -> () {
    let old = pool_directory(old_name);
    let new = pool_directory(new_name);
    if let Err(e) = fs::rename(&old, &new) {
        warn!(
            "unable to rename pool directory old {:?}, new {:?}, reason {:?}",
            old, new, e
        );
    }
}

/// Create a symlink to the new filesystem's block device within its pool's
/// directory.
pub fn filesystem_added(pool_name: &str, fs_name: &str, devnode: &Path) -> () {
    let p = filesystem_mount_path(pool_name, fs_name);

    // Remove existing and recreate to ensure it points to the correct devnode
    let _ = fs::remove_file(&p);
    if let Err(e) = symlink(devnode, &p) {
        warn!(
            "unable to create symlink for {:?} -> {:?}, reason {:?}",
            devnode, p, e
        );
    }
}

/// Remove the symlink when the filesystem is destroyed.
pub fn filesystem_removed(pool_name: &str, fs_name: &str) -> () {
    let p = filesystem_mount_path(pool_name, fs_name);
    if let Err(e) = fs::remove_file(&p) {
        warn!(
            "unable to remove symlink for filesystem {:?}, reason {:?}",
            p, e
        );
    }
}

/// Rename the symlink to track the filesystem's new name.
pub fn filesystem_renamed(pool_name: &str, old_name: &str, new_name: &str) -> () {
    let old = filesystem_mount_path(pool_name, old_name);
    let new = filesystem_mount_path(pool_name, new_name);
    if let Err(e) = fs::rename(&old, &new) {
        warn!(
            "unable to rename filesystem symlink for {:?} -> {:?}, reason {:?}",
            old, new, e
        );
    }
}

/// Given a pool name, synthesize a pool directory name for storing filesystem
/// mount paths.
fn pool_directory<T: AsRef<str>>(pool_name: T) -> PathBuf {
    vec![DEV_PATH, pool_name.as_ref()].iter().collect()
}

/// Given a pool name and a filesystem name, return the path it should be
/// available as a device for mounting.
pub fn filesystem_mount_path<T: AsRef<str>>(pool_name: T, fs_name: T) -> PathBuf {
    vec![DEV_PATH, pool_name.as_ref(), fs_name.as_ref()]
        .iter()
        .collect()
}
<|endoftext|>


<commit_before>#[cfg(feature = "model")]
use hyper::Client as HyperClient;
#[cfg(feature = "model")]
use std::io::Read;
#[cfg(feature = "model")]
use internal::prelude::*;

/// A file uploaded with a message. Not to be confused with [`Embed`]s.
///
/// [`Embed`]: struct.Embed.html
#[derive(Clone, Debug, Deserialize)]
pub struct Attachment {
    /// The unique ID given to this attachment.
    pub id: String,
    /// The filename of the file that was uploaded. This is equivalent to what
    /// the uploader had their file named.
    pub filename: String,
    /// If the attachment is an image, then the height of the image is provided.
    pub height: Option<u64>,
    /// The proxy URL.
    pub proxy_url: String,
    /// The size of the file in bytes.
    pub size: u64,
    /// The URL of the uploaded attachment.
    pub url: String,
    /// If the attachment is an image, then the widfth of the image is provided.
    pub width: Option<u64>,
}

#[cfg(feature = "model")]
impl Attachment {
    /// If this attachment is an image, then a tuple of the width and height
    /// in pixels is returned.
    pub fn dimensions(&self) -> Option<(u64, u64)> {
        self.width
            .and_then(|width| self.height.map(|height| (width, height)))
    }

    /// Downloads the attachment, returning back a vector of bytes.
    ///
    /// # Examples
    ///
    /// Download all of the attachments associated with a [`Message`]:
    ///
    /// ```rust,no_run
    /// use serenity::prelude::*;
    /// use serenity::model::*;
    /// use std::env;
    /// use std::fs::File;
    /// use std::io::Write;
    /// use std::path::Path;
    ///
    /// struct Handler;
    ///
    ///
    /// impl EventHandler for Handler {
    ///     fn on_message(&self, _: Context, message: Message) {
    ///         for attachment in message.attachments {
    ///             let content = match attachment.download() {
    ///                 Ok(content) => content,
    ///                 Err(why) => {
    ///                     println!("Error downloading attachment: {:?}", why);
    ///                     let _ = message.channel_id.say("Error downloading attachment");
    ///
    ///                     return;
    ///                 },
    ///             };
    ///
    ///             let mut file = match File::create(&attachment.filename) {
    ///                 Ok(file) => file,
    ///                 Err(why) => {
    ///                     println!("Error creating file: {:?}", why);
    ///                     let _ = message.channel_id.say("Error creating file");
    ///
    ///                     return;
    ///                 },
    ///             };
    ///
    ///             if let Err(why) = file.write(&content) {
    ///                 println!("Error writing to file: {:?}", why);
    ///
    ///                 return;
    ///             }
    ///
    ///             let _ = message.channel_id.say(&format!("Saved {:?}", attachment.filename));
    ///         }
    ///     }
    ///
    ///     fn on_ready(&self, _: Context, ready: Ready) {
    ///         println!("{} is connected!", ready.user.name);
    ///     }
    /// }
    /// let token = env::var("DISCORD_TOKEN").expect("token in environment");
    /// let mut client = Client::new(&token, Handler); client.start().unwrap();
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an [`Error::Io`] when there is a problem reading the contents
    /// of the HTTP response.
    ///
    /// Returns an [`Error::Hyper`] when there is a problem retrieving the
    /// attachment.
    ///
    /// [`Error::Hyper`]: ../enum.Error.html#variant.Hyper
    /// [`Error::Io`]: ../enum.Error.html#variant.Io
    /// [`Message`]: struct.Message.html
    pub fn download(&self) -> Result<Vec<u8>> {
        let hyper = HyperClient::new();
        let mut response = hyper.get(&self.url).send()?;

        let mut bytes = vec![];
        response.read_to_end(&mut bytes)?;

        Ok(bytes)
    }
}
<commit_msg>Use `request_client!` for attachment downloading (#165)<commit_after>#[cfg(feature = "model")]
use hyper::Client as HyperClient;
#[cfg(feature = "model")]
use std::io::Read;
#[cfg(feature = "model")]
use internal::prelude::*;

/// A file uploaded with a message. Not to be confused with [`Embed`]s.
///
/// [`Embed`]: struct.Embed.html
#[derive(Clone, Debug, Deserialize)]
pub struct Attachment {
    /// The unique ID given to this attachment.
    pub id: String,
    /// The filename of the file that was uploaded. This is equivalent to what
    /// the uploader had their file named.
    pub filename: String,
    /// If the attachment is an image, then the height of the image is provided.
    pub height: Option<u64>,
    /// The proxy URL.
    pub proxy_url: String,
    /// The size of the file in bytes.
    pub size: u64,
    /// The URL of the uploaded attachment.
    pub url: String,
    /// If the attachment is an image, then the widfth of the image is provided.
    pub width: Option<u64>,
}

#[cfg(feature = "model")]
impl Attachment {
    /// If this attachment is an image, then a tuple of the width and height
    /// in pixels is returned.
    pub fn dimensions(&self) -> Option<(u64, u64)> {
        self.width
            .and_then(|width| self.height.map(|height| (width, height)))
    }

    /// Downloads the attachment, returning back a vector of bytes.
    ///
    /// # Examples
    ///
    /// Download all of the attachments associated with a [`Message`]:
    ///
    /// ```rust,no_run
    /// use serenity::prelude::*;
    /// use serenity::model::*;
    /// use std::env;
    /// use std::fs::File;
    /// use std::io::Write;
    /// use std::path::Path;
    ///
    /// struct Handler;
    ///
    ///
    /// impl EventHandler for Handler {
    ///     fn on_message(&self, _: Context, message: Message) {
    ///         for attachment in message.attachments {
    ///             let content = match attachment.download() {
    ///                 Ok(content) => content,
    ///                 Err(why) => {
    ///                     println!("Error downloading attachment: {:?}", why);
    ///                     let _ = message.channel_id.say("Error downloading attachment");
    ///
    ///                     return;
    ///                 },
    ///             };
    ///
    ///             let mut file = match File::create(&attachment.filename) {
    ///                 Ok(file) => file,
    ///                 Err(why) => {
    ///                     println!("Error creating file: {:?}", why);
    ///                     let _ = message.channel_id.say("Error creating file");
    ///
    ///                     return;
    ///                 },
    ///             };
    ///
    ///             if let Err(why) = file.write(&content) {
    ///                 println!("Error writing to file: {:?}", why);
    ///
    ///                 return;
    ///             }
    ///
    ///             let _ = message.channel_id.say(&format!("Saved {:?}", attachment.filename));
    ///         }
    ///     }
    ///
    ///     fn on_ready(&self, _: Context, ready: Ready) {
    ///         println!("{} is connected!", ready.user.name);
    ///     }
    /// }
    /// let token = env::var("DISCORD_TOKEN").expect("token in environment");
    /// let mut client = Client::new(&token, Handler); client.start().unwrap();
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an [`Error::Io`] when there is a problem reading the contents
    /// of the HTTP response.
    ///
    /// Returns an [`Error::Hyper`] when there is a problem retrieving the
    /// attachment.
    ///
    /// [`Error::Hyper`]: ../enum.Error.html#variant.Hyper
    /// [`Error::Io`]: ../enum.Error.html#variant.Io
    /// [`Message`]: struct.Message.html
    pub fn download(&self) -> Result<Vec<u8>> {
        let hyper = request_client!();
        let mut response = hyper.get(&self.url).send()?;

        let mut bytes = vec![];
        response.read_to_end(&mut bytes)?;

        Ok(bytes)
    }
}
<|endoftext|>


<commit_before>use future::client::{Client as FutureClient, ClientExt as FutureClientExt,
                     Options as FutureOptions};
use futures::{Future, Stream};
use serde::Serialize;
use serde::de::DeserializeOwned;
use std::fmt;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::mpsc;
use std::thread;
#[cfg(feature = "tls")]
use tls::client::Context;
use tokio_core::reactor;
use tokio_proto::util::client_proxy::{ClientProxy, Receiver, pair};
use tokio_service::Service;
use util::FirstSocketAddr;

#[doc(hidden)]
pub struct Client<Req, Resp, E> {
    proxy: ClientProxy<Req, Resp, ::Error<E>>,
}

impl<Req, Resp, E> Clone for Client<Req, Resp, E> {
    fn clone(&self) -> Self {
        Client {
            proxy: self.proxy.clone(),
        }
    }
}

impl<Req, Resp, E> fmt::Debug for Client<Req, Resp, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        const PROXY: &str = "ClientProxy { .. }";
        f.debug_struct("Client").field("proxy", &PROXY).finish()
    }
}

impl<Req, Resp, E> Client<Req, Resp, E>
where
    Req: Serialize + Send + 'static,
    Resp: DeserializeOwned + Send + 'static,
    E: DeserializeOwned + Send + 'static,
{
    /// Drives an RPC call for the given request.
    pub fn call(&self, request: Req) -> Result<Resp, ::Error<E>> {
        // Must call wait here to block on the response.
        // The request handler relies on this fact to safely unwrap the
        // oneshot send.
        self.proxy.call(request).wait()
    }
}

/// Additional options to configure how the client connects and operates.
pub struct Options {
    /// Max packet size in bytes.
    max_payload_size: u64,
    #[cfg(feature = "tls")]
    tls_ctx: Option<Context>,
}

impl Default for Options {
    #[cfg(not(feature = "tls"))]
    fn default() -> Self {
        Options {
            max_payload_size: 2_000_000,
        }
    }

    #[cfg(feature = "tls")]
    fn default() -> Self {
        Options {
            max_payload_size: 2_000_000,
            tls_ctx: None,
        }
    }
}

impl Options {
    /// Set the max payload size in bytes. The default is 2,000,000 (2 MB).
    pub fn max_payload_size(mut self, bytes: u64) -> Self {
        self.max_payload_size = bytes;
        self
    }

    /// Connect using the given `Context`
    #[cfg(feature = "tls")]
    pub fn tls(mut self, ctx: Context) -> Self {
        self.tls_ctx = Some(ctx);
        self
    }
}

impl fmt::Debug for Options {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        #[cfg(feature = "tls")]
        const SOME: &str = "Some(_)";
        #[cfg(feature = "tls")]
        const NONE: &str = "None";
        let mut f = f.debug_struct("Options");
        #[cfg(feature = "tls")] f.field("tls_ctx", if self.tls_ctx.is_some() { &SOME } else { &NONE });
        f.finish()
    }
}

impl Into<FutureOptions> for (reactor::Handle, Options) {
    #[cfg(feature = "tls")]
    fn into(self) -> FutureOptions {
        let (handle, options) = self;
        let mut opts = FutureOptions::default().handle(handle);
        if let Some(tls_ctx) = options.tls_ctx {
            opts = opts.tls(tls_ctx);
        }
        opts
    }

    #[cfg(not(feature = "tls"))]
    fn into(self) -> FutureOptions {
        let (handle, _) = self;
        FutureOptions::default().handle(handle)
    }
}

/// Extension methods for Clients.
pub trait ClientExt: Sized {
    /// Connects to a server located at the given address.
    fn connect<A>(addr: A, options: Options) -> io::Result<Self>
    where
        A: ToSocketAddrs;
}

impl<Req, Resp, E> ClientExt for Client<Req, Resp, E>
where
    Req: Serialize + Send + 'static,
    Resp: DeserializeOwned + Send + 'static,
    E: DeserializeOwned + Send + 'static,
{
    fn connect<A>(addr: A, options: Options) -> io::Result<Self>
    where
        A: ToSocketAddrs,
    {
        let addr = addr.try_first_socket_addr()?;
        let (connect_tx, connect_rx) = mpsc::channel();
        thread::spawn(move || match RequestHandler::connect(addr, options) {
            Ok((proxy, mut handler)) => {
                connect_tx.send(Ok(proxy)).unwrap();
                handler.handle_requests();
            }
            Err(e) => connect_tx.send(Err(e)).unwrap(),
        });
        Ok(connect_rx.recv().unwrap()?)
    }
}

/// Forwards incoming requests of type `Req`
/// with expected response `Result<Resp, ::Error<E>>`
/// to service `S`.
struct RequestHandler<Req, Resp, E, S> {
    reactor: reactor::Core,
    client: S,
    requests: Receiver<Req, Resp, ::Error<E>>,
}

impl<Req, Resp, E> RequestHandler<Req, Resp, E, FutureClient<Req, Resp, E>>
where
    Req: Serialize + Send + 'static,
    Resp: DeserializeOwned + Send + 'static,
    E: DeserializeOwned + Send + 'static,
{
    /// Creates a new `RequestHandler` by connecting a `FutureClient` to the given address
    /// using the given options.
    fn connect(addr: SocketAddr, options: Options) -> io::Result<(Client<Req, Resp, E>, Self)> {
        let mut reactor = reactor::Core::new()?;
        let options = (reactor.handle(), options).into();
        let client = reactor.run(FutureClient::connect(addr, options))?;
        let (proxy, requests) = pair();
        Ok((
            Client { proxy },
            RequestHandler {
                reactor,
                client,
                requests,
            },
        ))
    }
}

impl<Req, Resp, E, S> RequestHandler<Req, Resp, E, S>
where
    Req: Serialize + 'static,
    Resp: DeserializeOwned + 'static,
    E: DeserializeOwned + 'static,
    S: Service<Request = Req, Response = Resp, Error = ::Error<E>>,
    S::Future: 'static,
{
    fn handle_requests(&mut self) {
        let RequestHandler {
            ref mut reactor,
            ref mut requests,
            ref mut client,
        } = *self;
        let handle = reactor.handle();
        let requests = requests
            .map(|result| {
                match result {
                    Ok(req) => req,
                    // The ClientProxy never sends Err currently
                    Err(e) => panic!("Unimplemented error handling in RequestHandler: {}", e),
                }
            })
            .for_each(|(request, response_tx)| {
                let request = client.call(request).then(move |response| {
                    // Safe to unwrap because clients always block on the response future.
                    response_tx
                        .send(response)
                        .map_err(|_| ())
                        .expect("Client should block on response");
                    Ok(())
                });
                handle.spawn(request);
                Ok(())
            });
        reactor.run(requests).unwrap();
    }
}

#[test]
fn handle_requests() {
    use futures::future;

    struct Client;
    impl Service for Client {
        type Request = i32;
        type Response = i32;
        type Error = ::Error<()>;
        type Future = future::FutureResult<i32, ::Error<()>>;

        fn call(&self, req: i32) -> Self::Future {
            future::ok(req)
        }
    }

    let (request, requests) = ::futures::sync::mpsc::unbounded();
    let reactor = reactor::Core::new().unwrap();
    let client = Client;
    let mut request_handler = RequestHandler {
        reactor,
        client,
        requests,
    };
    // Test that `handle_requests` returns when all request senders are dropped.
    drop(request);
    request_handler.handle_requests();
}
<commit_msg>Do not ignore payload size in sync client (#194)<commit_after>use future::client::{Client as FutureClient, ClientExt as FutureClientExt,
                     Options as FutureOptions};
use futures::{Future, Stream};
use serde::Serialize;
use serde::de::DeserializeOwned;
use std::fmt;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::mpsc;
use std::thread;
#[cfg(feature = "tls")]
use tls::client::Context;
use tokio_core::reactor;
use tokio_proto::util::client_proxy::{ClientProxy, Receiver, pair};
use tokio_service::Service;
use util::FirstSocketAddr;

#[doc(hidden)]
pub struct Client<Req, Resp, E> {
    proxy: ClientProxy<Req, Resp, ::Error<E>>,
}

impl<Req, Resp, E> Clone for Client<Req, Resp, E> {
    fn clone(&self) -> Self {
        Client {
            proxy: self.proxy.clone(),
        }
    }
}

impl<Req, Resp, E> fmt::Debug for Client<Req, Resp, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        const PROXY: &str = "ClientProxy { .. }";
        f.debug_struct("Client").field("proxy", &PROXY).finish()
    }
}

impl<Req, Resp, E> Client<Req, Resp, E>
where
    Req: Serialize + Send + 'static,
    Resp: DeserializeOwned + Send + 'static,
    E: DeserializeOwned + Send + 'static,
{
    /// Drives an RPC call for the given request.
    pub fn call(&self, request: Req) -> Result<Resp, ::Error<E>> {
        // Must call wait here to block on the response.
        // The request handler relies on this fact to safely unwrap the
        // oneshot send.
        self.proxy.call(request).wait()
    }
}

/// Additional options to configure how the client connects and operates.
pub struct Options {
    /// Max packet size in bytes.
    max_payload_size: u64,
    #[cfg(feature = "tls")]
    tls_ctx: Option<Context>,
}

impl Default for Options {
    #[cfg(not(feature = "tls"))]
    fn default() -> Self {
        Options {
            max_payload_size: 2_000_000,
        }
    }

    #[cfg(feature = "tls")]
    fn default() -> Self {
        Options {
            max_payload_size: 2_000_000,
            tls_ctx: None,
        }
    }
}

impl Options {
    /// Set the max payload size in bytes. The default is 2,000,000 (2 MB).
    pub fn max_payload_size(mut self, bytes: u64) -> Self {
        self.max_payload_size = bytes;
        self
    }

    /// Connect using the given `Context`
    #[cfg(feature = "tls")]
    pub fn tls(mut self, ctx: Context) -> Self {
        self.tls_ctx = Some(ctx);
        self
    }
}

impl fmt::Debug for Options {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        #[cfg(feature = "tls")]
        const SOME: &str = "Some(_)";
        #[cfg(feature = "tls")]
        const NONE: &str = "None";
        let mut f = f.debug_struct("Options");
        #[cfg(feature = "tls")] f.field("tls_ctx", if self.tls_ctx.is_some() { &SOME } else { &NONE });
        f.finish()
    }
}

impl Into<FutureOptions> for (reactor::Handle, Options) {
    #[cfg(feature = "tls")]
    fn into(self) -> FutureOptions {
        let (handle, options) = self;
        let mut opts = FutureOptions::default().max_payload_size(options.max_payload_size).handle(handle);
        if let Some(tls_ctx) = options.tls_ctx {
            opts = opts.tls(tls_ctx);
        }
        opts
    }

    #[cfg(not(feature = "tls"))]
    fn into(self) -> FutureOptions {
        let (handle, options) = self;
        FutureOptions::default().max_payload_size(options.max_payload_size).handle(handle)
    }
}

/// Extension methods for Clients.
pub trait ClientExt: Sized {
    /// Connects to a server located at the given address.
    fn connect<A>(addr: A, options: Options) -> io::Result<Self>
    where
        A: ToSocketAddrs;
}

impl<Req, Resp, E> ClientExt for Client<Req, Resp, E>
where
    Req: Serialize + Send + 'static,
    Resp: DeserializeOwned + Send + 'static,
    E: DeserializeOwned + Send + 'static,
{
    fn connect<A>(addr: A, options: Options) -> io::Result<Self>
    where
        A: ToSocketAddrs,
    {
        let addr = addr.try_first_socket_addr()?;
        let (connect_tx, connect_rx) = mpsc::channel();
        thread::spawn(move || match RequestHandler::connect(addr, options) {
            Ok((proxy, mut handler)) => {
                connect_tx.send(Ok(proxy)).unwrap();
                handler.handle_requests();
            }
            Err(e) => connect_tx.send(Err(e)).unwrap(),
        });
        Ok(connect_rx.recv().unwrap()?)
    }
}

/// Forwards incoming requests of type `Req`
/// with expected response `Result<Resp, ::Error<E>>`
/// to service `S`.
struct RequestHandler<Req, Resp, E, S> {
    reactor: reactor::Core,
    client: S,
    requests: Receiver<Req, Resp, ::Error<E>>,
}

impl<Req, Resp, E> RequestHandler<Req, Resp, E, FutureClient<Req, Resp, E>>
where
    Req: Serialize + Send + 'static,
    Resp: DeserializeOwned + Send + 'static,
    E: DeserializeOwned + Send + 'static,
{
    /// Creates a new `RequestHandler` by connecting a `FutureClient` to the given address
    /// using the given options.
    fn connect(addr: SocketAddr, options: Options) -> io::Result<(Client<Req, Resp, E>, Self)> {
        let mut reactor = reactor::Core::new()?;
        let options = (reactor.handle(), options).into();
        let client = reactor.run(FutureClient::connect(addr, options))?;
        let (proxy, requests) = pair();
        Ok((
            Client { proxy },
            RequestHandler {
                reactor,
                client,
                requests,
            },
        ))
    }
}

impl<Req, Resp, E, S> RequestHandler<Req, Resp, E, S>
where
    Req: Serialize + 'static,
    Resp: DeserializeOwned + 'static,
    E: DeserializeOwned + 'static,
    S: Service<Request = Req, Response = Resp, Error = ::Error<E>>,
    S::Future: 'static,
{
    fn handle_requests(&mut self) {
        let RequestHandler {
            ref mut reactor,
            ref mut requests,
            ref mut client,
        } = *self;
        let handle = reactor.handle();
        let requests = requests
            .map(|result| {
                match result {
                    Ok(req) => req,
                    // The ClientProxy never sends Err currently
                    Err(e) => panic!("Unimplemented error handling in RequestHandler: {}", e),
                }
            })
            .for_each(|(request, response_tx)| {
                let request = client.call(request).then(move |response| {
                    // Safe to unwrap because clients always block on the response future.
                    response_tx
                        .send(response)
                        .map_err(|_| ())
                        .expect("Client should block on response");
                    Ok(())
                });
                handle.spawn(request);
                Ok(())
            });
        reactor.run(requests).unwrap();
    }
}

#[test]
fn handle_requests() {
    use futures::future;

    struct Client;
    impl Service for Client {
        type Request = i32;
        type Response = i32;
        type Error = ::Error<()>;
        type Future = future::FutureResult<i32, ::Error<()>>;

        fn call(&self, req: i32) -> Self::Future {
            future::ok(req)
        }
    }

    let (request, requests) = ::futures::sync::mpsc::unbounded();
    let reactor = reactor::Core::new().unwrap();
    let client = Client;
    let mut request_handler = RequestHandler {
        reactor,
        client,
        requests,
    };
    // Test that `handle_requests` returns when all request senders are dropped.
    drop(request);
    request_handler.handle_requests();
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{ULONG, DWORD, WSABUF, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr() as *const _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_mut_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let mut flags = 0;
            let ret = WSARecv(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                &mut flags,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let acceptor = TcpListener::bind("127.0.0.1:3444").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<commit_msg>cast to *mut i8 for windows<commit_after>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{ULONG, DWORD, WSABUF, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_mut_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let mut flags = 0;
            let ret = WSARecv(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                &mut flags,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let acceptor = TcpListener::bind("127.0.0.1:3444").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<|endoftext|>