<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub mod convert;
pub mod path;

use std::path::PathBuf;

use convert::FromLossy;

use rrg_macro::ack;

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

pub mod protobuf {
    include!(concat!(env!("OUT_DIR"), "/proto/mod.rs"));
}

impl From<bool> for DataBlob {

    fn from(value: bool) -> DataBlob {
        DataBlob {
            boolean: Some(value),
            ..Default::default()
        }
    }
}

impl From<i64> for DataBlob {

    fn from(value: i64) -> DataBlob {
        DataBlob {
            integer: Some(value),
            ..Default::default()
        }
    }
}

impl From<f32> for DataBlob {

    fn from(value: f32) -> DataBlob {
        DataBlob {
            float: Some(value),
            ..Default::default()
        }
    }
}

impl From<Vec<u8>> for DataBlob {

    fn from(value: Vec<u8>) -> DataBlob {
        DataBlob {
            data: Some(value),
            ..Default::default()
        }
    }
}

impl From<String> for DataBlob {

    fn from(value: String) -> DataBlob  {
        DataBlob {
            string: Some(value),
            ..Default::default()
        }
    }
}

impl KeyValue {

    /// Creates an empty key-value.
    ///
    /// Both the key and the value are going to be equal to `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::empty();
    /// assert_eq!(entry.k, None);
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn empty() -> KeyValue {
        KeyValue {
            k: None,
            v: None,
        }
    }

    /// Creates a key-value pair.
    ///
    /// Both the key and the value are going to be equal to the given values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::pair(String::from("foo"), 42i64);
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("foo")));
    /// assert_eq!(entry.v.unwrap().integer, Some(42));
    /// ```
    pub fn pair<K, V>(key: K, value: V) -> KeyValue
    where
        K: Into<DataBlob>,
        V: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: Some(value.into()),
        }
    }

    /// Creates a key-only key-value.
    ///
    /// The key is going to be equal to the given value and the key will be
    /// `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::key(String::from("quux"));
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("quux")));
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn key<K>(key: K) -> KeyValue
    where
        K: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: None,
        }
    }
}

impl std::iter::FromIterator<KeyValue> for AttributedDict {

    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = KeyValue>,
    {
        AttributedDict {
            dat: iter.into_iter().collect(),
        }
    }
}

impl<K, V> std::iter::FromIterator<(K, V)> for AttributedDict
where
    K: Into<DataBlob>,
    V: Into<DataBlob>,
{
    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let pair = |(key, value)| KeyValue::pair(key, value);
        iter.into_iter().map(pair).collect()
    }
}

impl FromLossy<std::fs::Metadata> for StatEntry {

    fn from_lossy(metadata: std::fs::Metadata) -> StatEntry {
        #[cfg(target_family = "unix")]
        use std::convert::{TryFrom, TryInto};
        #[cfg(target_family = "unix")]
        use std::os::unix::fs::MetadataExt;

        // TODO: Fix definition of `StatEntry`.
        // `StatEntry` defines insufficient integer width for some fields. For
        // now we just ignore errors, but the definition should be improved.
        #[cfg(target_family = "unix")]
        let some = |value: u64| Some(value.try_into().unwrap_or(0));

        let atime_secs = ack! {
            metadata.accessed(),
            error: "failed to obtain file access time"
        }.and_then(|atime| ack! {
            secs(atime),
            error: "failed to convert access time to seconds"
        });

        let mtime_secs = ack! {
            metadata.modified(),
            error: "failed to obtain file modification time"
        }.and_then(|mtime| ack! {
            secs(mtime),
            error: "failed to convert modification time to seconds"
        });

        let btime_secs = ack! {
            metadata.created(),
            error: "failed to obtain file creation time"
        }.and_then(|btime| ack! {
            secs(btime),
            error: "failed to convert creation time to seconds"
        });

        #[cfg(target_family = "unix")]
        let ctime_secs = ack! {
            u64::try_from(metadata.ctime()),
            error: "negative inode change time"
        };

        StatEntry {
            #[cfg(target_family = "unix")]
            st_mode: Some(metadata.mode().into()),
            #[cfg(target_family = "unix")]
            st_ino: some(metadata.ino()),
            #[cfg(target_family = "unix")]
            st_dev: some(metadata.dev()),
            #[cfg(target_family = "unix")]
            st_rdev: some(metadata.rdev()),
            #[cfg(target_family = "unix")]
            st_nlink: some(metadata.nlink()),
            #[cfg(target_family = "unix")]
            st_uid: Some(metadata.uid()),
            #[cfg(target_family = "unix")]
            st_gid: Some(metadata.gid()),
            st_size: Some(metadata.len()),
            st_atime: atime_secs,
            st_mtime: mtime_secs,
            #[cfg(target_family = "unix")]
            st_ctime: ctime_secs,
            st_btime: btime_secs,
            #[cfg(target_family = "unix")]
            st_blocks: some(metadata.blocks()),
            #[cfg(target_family = "unix")]
            st_blksize: some(metadata.blksize()),
            ..Default::default()
        }
    }
}

/// An error type for situations where parsing path specification failed.
#[derive(Clone, Debug)]
pub enum ParsePathSpecError {
    /// Attempted to parse an empty path.
    Empty,
    /// Attempted to parse a path of unknown type.
    UnknownType(i32),
    /// Attempted to parse a path of invalid type.
    InvalidType(path_spec::PathType),
}

impl std::fmt::Display for ParsePathSpecError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use ParsePathSpecError::*;

        match *self {
            Empty => {
                write!(fmt, "empty path")
            }
            UnknownType(value) => {
                write!(fmt, "unknown path type value: {}", value)
            }
            InvalidType(value) => {
                write!(fmt, "invalid path type: {:?}", value)
            }
        }
    }
}

impl std::error::Error for ParsePathSpecError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl std::convert::TryFrom<PathSpec> for PathBuf {

    type Error = ParsePathSpecError;

    fn try_from(spec: PathSpec) -> Result<PathBuf, ParsePathSpecError> {
        use ParsePathSpecError::*;

        let path_type = spec.pathtype.unwrap_or_default();
        match path_spec::PathType::from_i32(path_type) {
            Some(path_spec::PathType::Os) => (),
            Some(path_type) => return Err(InvalidType(path_type)),
            None => return Err(UnknownType(path_type)),
        };

        match spec.path {
            Some(path) if path.len() > 0 => Ok(PathBuf::from(path)),
            _ => Err(ParsePathSpecError::Empty),
        }
    }
}

impl From<PathBuf> for PathSpec {

    fn from(path: PathBuf) -> PathSpec {
        PathSpec {
            path: Some(path.to_string_lossy().into_owned()),
            pathtype: Some(path_spec::PathType::Os.into()),
            ..Default::default()
        }
    }
}

/// An error type for failures that can occur when converting timestamps.
#[derive(Clone, Debug)]
pub enum TimeConversionError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl TimeConversionError {

    /// Creates a conversion error from an integer overflow error.
    pub fn overflow(error: std::num::TryFromIntError) -> TimeConversionError {
        TimeConversionError::Overflow(error)
    }
}

impl std::fmt::Display for TimeConversionError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for TimeConversionError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for TimeConversionError {

    fn from(error: std::time::SystemTimeError) -> TimeConversionError {
        TimeConversionError::Epoch(error)
    }
}

/// Converts system time into epoch nanoseconds.
///
/// Some GRR messages use epoch nanoseconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::nanos;
///
/// assert_eq!(nanos(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn nanos(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    use std::convert::TryInto as _;

    let duration = time.duration_since(std::time::UNIX_EPOCH)?;
    duration.as_nanos().try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    use std::convert::TryInto as _;

    let duration = std::time::Duration::from_nanos(nanos(time)?);
    duration.as_micros().try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch seconds.
///
/// Some GRR messages use epoch seconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::secs;
///
/// assert_eq!(secs(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn secs(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    let duration = std::time::Duration::from_nanos(nanos(time)?);
    Ok(duration.as_secs())
}
<commit_msg>Implement conversion traits for data blobs.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub mod convert;
pub mod path;

use std::path::PathBuf;

use convert::FromLossy;

use rrg_macro::ack;

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

pub mod protobuf {
    include!(concat!(env!("OUT_DIR"), "/proto/mod.rs"));

    impl From<bool> for jobs::DataBlob {

        fn from(value: bool) -> jobs::DataBlob {
            let mut result = jobs::DataBlob::new();
            result.set_boolean(value);

            result
        }
    }

    impl From<i64> for jobs::DataBlob {

        fn from(value: i64) -> jobs::DataBlob {
            let mut result = jobs::DataBlob::new();
            result.set_integer(value);

            result
        }
    }

    impl From<f32> for jobs::DataBlob {

        fn from(value: f32) -> jobs::DataBlob {
            let mut result = jobs::DataBlob::new();
            result.set_float(value);

            result
        }
    }

    impl From<Vec<u8>> for jobs::DataBlob {

        fn from(value: Vec<u8>) -> jobs::DataBlob {
            let mut result = jobs::DataBlob::new();
            result.set_data(value);

            result
        }
    }

    impl From<String> for jobs::DataBlob {

        fn from(value: String) -> jobs::DataBlob {
            let mut result = jobs::DataBlob::new();
            result.set_string(value);

            result
        }
    }
}

impl From<bool> for DataBlob {

    fn from(value: bool) -> DataBlob {
        DataBlob {
            boolean: Some(value),
            ..Default::default()
        }
    }
}

impl From<i64> for DataBlob {

    fn from(value: i64) -> DataBlob {
        DataBlob {
            integer: Some(value),
            ..Default::default()
        }
    }
}

impl From<f32> for DataBlob {

    fn from(value: f32) -> DataBlob {
        DataBlob {
            float: Some(value),
            ..Default::default()
        }
    }
}

impl From<Vec<u8>> for DataBlob {

    fn from(value: Vec<u8>) -> DataBlob {
        DataBlob {
            data: Some(value),
            ..Default::default()
        }
    }
}

impl From<String> for DataBlob {

    fn from(value: String) -> DataBlob  {
        DataBlob {
            string: Some(value),
            ..Default::default()
        }
    }
}

impl KeyValue {

    /// Creates an empty key-value.
    ///
    /// Both the key and the value are going to be equal to `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::empty();
    /// assert_eq!(entry.k, None);
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn empty() -> KeyValue {
        KeyValue {
            k: None,
            v: None,
        }
    }

    /// Creates a key-value pair.
    ///
    /// Both the key and the value are going to be equal to the given values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::pair(String::from("foo"), 42i64);
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("foo")));
    /// assert_eq!(entry.v.unwrap().integer, Some(42));
    /// ```
    pub fn pair<K, V>(key: K, value: V) -> KeyValue
    where
        K: Into<DataBlob>,
        V: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: Some(value.into()),
        }
    }

    /// Creates a key-only key-value.
    ///
    /// The key is going to be equal to the given value and the key will be
    /// `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::key(String::from("quux"));
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("quux")));
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn key<K>(key: K) -> KeyValue
    where
        K: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: None,
        }
    }
}

impl std::iter::FromIterator<KeyValue> for AttributedDict {

    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = KeyValue>,
    {
        AttributedDict {
            dat: iter.into_iter().collect(),
        }
    }
}

impl<K, V> std::iter::FromIterator<(K, V)> for AttributedDict
where
    K: Into<DataBlob>,
    V: Into<DataBlob>,
{
    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let pair = |(key, value)| KeyValue::pair(key, value);
        iter.into_iter().map(pair).collect()
    }
}

impl FromLossy<std::fs::Metadata> for StatEntry {

    fn from_lossy(metadata: std::fs::Metadata) -> StatEntry {
        #[cfg(target_family = "unix")]
        use std::convert::{TryFrom, TryInto};
        #[cfg(target_family = "unix")]
        use std::os::unix::fs::MetadataExt;

        // TODO: Fix definition of `StatEntry`.
        // `StatEntry` defines insufficient integer width for some fields. For
        // now we just ignore errors, but the definition should be improved.
        #[cfg(target_family = "unix")]
        let some = |value: u64| Some(value.try_into().unwrap_or(0));

        let atime_secs = ack! {
            metadata.accessed(),
            error: "failed to obtain file access time"
        }.and_then(|atime| ack! {
            secs(atime),
            error: "failed to convert access time to seconds"
        });

        let mtime_secs = ack! {
            metadata.modified(),
            error: "failed to obtain file modification time"
        }.and_then(|mtime| ack! {
            secs(mtime),
            error: "failed to convert modification time to seconds"
        });

        let btime_secs = ack! {
            metadata.created(),
            error: "failed to obtain file creation time"
        }.and_then(|btime| ack! {
            secs(btime),
            error: "failed to convert creation time to seconds"
        });

        #[cfg(target_family = "unix")]
        let ctime_secs = ack! {
            u64::try_from(metadata.ctime()),
            error: "negative inode change time"
        };

        StatEntry {
            #[cfg(target_family = "unix")]
            st_mode: Some(metadata.mode().into()),
            #[cfg(target_family = "unix")]
            st_ino: some(metadata.ino()),
            #[cfg(target_family = "unix")]
            st_dev: some(metadata.dev()),
            #[cfg(target_family = "unix")]
            st_rdev: some(metadata.rdev()),
            #[cfg(target_family = "unix")]
            st_nlink: some(metadata.nlink()),
            #[cfg(target_family = "unix")]
            st_uid: Some(metadata.uid()),
            #[cfg(target_family = "unix")]
            st_gid: Some(metadata.gid()),
            st_size: Some(metadata.len()),
            st_atime: atime_secs,
            st_mtime: mtime_secs,
            #[cfg(target_family = "unix")]
            st_ctime: ctime_secs,
            st_btime: btime_secs,
            #[cfg(target_family = "unix")]
            st_blocks: some(metadata.blocks()),
            #[cfg(target_family = "unix")]
            st_blksize: some(metadata.blksize()),
            ..Default::default()
        }
    }
}

/// An error type for situations where parsing path specification failed.
#[derive(Clone, Debug)]
pub enum ParsePathSpecError {
    /// Attempted to parse an empty path.
    Empty,
    /// Attempted to parse a path of unknown type.
    UnknownType(i32),
    /// Attempted to parse a path of invalid type.
    InvalidType(path_spec::PathType),
}

impl std::fmt::Display for ParsePathSpecError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use ParsePathSpecError::*;

        match *self {
            Empty => {
                write!(fmt, "empty path")
            }
            UnknownType(value) => {
                write!(fmt, "unknown path type value: {}", value)
            }
            InvalidType(value) => {
                write!(fmt, "invalid path type: {:?}", value)
            }
        }
    }
}

impl std::error::Error for ParsePathSpecError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl std::convert::TryFrom<PathSpec> for PathBuf {

    type Error = ParsePathSpecError;

    fn try_from(spec: PathSpec) -> Result<PathBuf, ParsePathSpecError> {
        use ParsePathSpecError::*;

        let path_type = spec.pathtype.unwrap_or_default();
        match path_spec::PathType::from_i32(path_type) {
            Some(path_spec::PathType::Os) => (),
            Some(path_type) => return Err(InvalidType(path_type)),
            None => return Err(UnknownType(path_type)),
        };

        match spec.path {
            Some(path) if path.len() > 0 => Ok(PathBuf::from(path)),
            _ => Err(ParsePathSpecError::Empty),
        }
    }
}

impl From<PathBuf> for PathSpec {

    fn from(path: PathBuf) -> PathSpec {
        PathSpec {
            path: Some(path.to_string_lossy().into_owned()),
            pathtype: Some(path_spec::PathType::Os.into()),
            ..Default::default()
        }
    }
}

/// An error type for failures that can occur when converting timestamps.
#[derive(Clone, Debug)]
pub enum TimeConversionError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl TimeConversionError {

    /// Creates a conversion error from an integer overflow error.
    pub fn overflow(error: std::num::TryFromIntError) -> TimeConversionError {
        TimeConversionError::Overflow(error)
    }
}

impl std::fmt::Display for TimeConversionError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for TimeConversionError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for TimeConversionError {

    fn from(error: std::time::SystemTimeError) -> TimeConversionError {
        TimeConversionError::Epoch(error)
    }
}

/// Converts system time into epoch nanoseconds.
///
/// Some GRR messages use epoch nanoseconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::nanos;
///
/// assert_eq!(nanos(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn nanos(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    use std::convert::TryInto as _;

    let duration = time.duration_since(std::time::UNIX_EPOCH)?;
    duration.as_nanos().try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    use std::convert::TryInto as _;

    let duration = std::time::Duration::from_nanos(nanos(time)?);
    duration.as_micros().try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch seconds.
///
/// Some GRR messages use epoch seconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::secs;
///
/// assert_eq!(secs(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn secs(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    let duration = std::time::Duration::from_nanos(nanos(time)?);
    Ok(duration.as_secs())
}
<|endoftext|>


<commit_before>use super::TyCtxt;

use super::super::core::*;
use super::name_generator::*;

/// A context with the needed state to deal with operations that process an inductive definition.
pub struct RecursorCx<'i, 'tcx> {
    ty_cx: &'tcx mut TyCtxt,
    inductive_ty: &'i Data,
    ind_hyp: Name,
}

impl<'i, 'tcx> RecursorCx<'i, 'tcx> {
    fn new(ty_cx: &'tcx mut TyCtxt, inductive_ty: &'i Data) -> RecursorCx<'i, 'tcx> {

        let mut rcx = RecursorCx {
            ty_cx: ty_cx,
            inductive_ty: inductive_ty,
            ind_hyp: inductive_ty.name.clone(),
        };

        let ty = rcx.eta_expand();

        let params = inductive_ty.parameters.iter().map(|x| x.to_term()).collect();
        let ty = Term::apply_all(ty, params).whnf();
        let ind_hyp = rcx.ty_cx.local_with_repr("C".to_string(),
            Term::abstract_pi(vec![rcx.ty_cx.local_with_repr("".to_string(), ty)],
                Term::Type));

        rcx.ind_hyp = ind_hyp;

        rcx
    }

    fn eta_expand(&self) -> Term {
        let mut pi = self.inductive_ty.ty.clone();
        let mut result = self.inductive_ty.name.to_term();
        let mut i = 0;
        let mut locals = vec![];
        while let Term::Forall { ty, term, .. } = pi {
            let local = self.ty_cx.local_with_repr(format!("x{}", 0), *ty);
            locals.push(local);
            pi = *term;
        }
        Term::abstract_lambda(
            locals.clone(),
            Term::apply_all(result, locals.into_iter().map(|t| t.to_term()).collect()))
    }

    pub fn make_premise(&mut self, ind_hyp: &Name, ctor: &(Name, Term)) -> Term {
        let ctor_name = &ctor.0;
        let mut ctor_ty = &ctor.1;

        let mut premise_args = Vec::new();
        let mut names = Vec::new();

        let mut i = 0;
        while let &Term::Forall { ref ty, ref term, .. } = ctor_ty {
            let local_n = self.ty_cx.local_with_repr(format!("a{}", i), *ty.clone());

            premise_args.push(local_n.clone());

            let local_x =
                self.ty_cx.local_with_repr(
                    "".to_string(),
                    Term::apply(ind_hyp.to_term(), local_n.to_term()));

            premise_args.push(local_x);

            if true {
                names.push(local_n.to_term());
            }

            ctor_ty = &**term;
            i += 1;
        }

        let c_for_ctor = Term::apply(
            ind_hyp.to_term(),
            Term::apply_all(ctor_name.to_term(), names));

        Term::abstract_pi(premise_args, c_for_ctor)
    }
}

/// Construct a recursor for `data_type`.
pub fn make_recursor(ty_cx: &mut TyCtxt, data_type: &Data) {
    let mut rcx = RecursorCx::new(ty_cx, data_type);

    let params = data_type.parameters.clone();

    let ind_hyp = rcx.ind_hyp.clone();

    let mut premises = Vec::new();

    for ctor in &data_type.ctors {
        premises.push(rcx.make_premise(&ind_hyp, ctor))
    }

    let premises: Vec<_> = premises.into_iter()
                                   .map(|p| rcx.ty_cx.local_with_repr("".to_string(), p))
                                   .collect();

    let mut result = data_type.ty.clone();

    let mut tys = Vec::new();
    while let Term::Forall { ty, term, .. } = result {
        tys.push(*ty.clone());
        result = *term;
    }

    tys.push(data_type.name.to_term());

    let tys: Vec<_> = tys.into_iter()
                         .enumerate()
                         .map(|(i, ty)| rcx.ty_cx.local_with_repr(format!("a{}", i), ty))
                         .collect();

    let tys_terms: Vec<_> = tys.iter().map(|t| t.to_term()).collect();

    let recursor_ty =
        Term::abstract_pi(
            params.clone(),
            Term::abstract_pi(vec![ind_hyp.clone()],
                Term::abstract_pi(premises.clone(),
                    Term::abstract_pi(tys.clone(),
                        Term::apply_all(ind_hyp.to_term(),
                        tys_terms.clone())))));

    // println!("declare_datatype: recursor_ty={}", recursor_ty);

    let mut inner_terms = vec![ind_hyp.clone().to_term()];
    inner_terms.extend(premises.clone().into_iter().map(|x| x.to_term()));
    inner_terms.extend(tys_terms.clone().into_iter());

    let recursor_body =
        Term::abstract_lambda(
            params.clone(),
            Term::abstract_lambda(
                vec![ind_hyp.clone()],
                Term::abstract_lambda(
                    premises,
                    Term::abstract_lambda(
                        tys,
                        Term::Recursor(
                            data_type.name.clone(),
                            1,
                            inner_terms)))));

    rcx.ty_cx.definitions.insert(data_type.name.in_scope("rec".to_string()).unwrap(),
                            (recursor_ty, recursor_body));
}
<commit_msg>List recursors nearly working<commit_after>use super::TyCtxt;

use super::super::core::*;
use super::name_generator::*;

/// A context with the needed state to deal with operations that process an inductive definition.
pub struct RecursorCx<'i, 'tcx> {
    ty_cx: &'tcx mut TyCtxt,
    inductive_ty: &'i Data,
    ind_hyp: Name,
}

impl<'i, 'tcx> RecursorCx<'i, 'tcx> {
    fn new(ty_cx: &'tcx mut TyCtxt, inductive_ty: &'i Data) -> RecursorCx<'i, 'tcx> {

        let mut rcx = RecursorCx {
            ty_cx: ty_cx,
            inductive_ty: inductive_ty,
            ind_hyp: inductive_ty.name.clone(),
        };

        let ty = rcx.eta_expand();

        let ty = rcx.with_params(ty);
        let ind_hyp = rcx.ty_cx.local_with_repr("C".to_string(),
            Term::abstract_pi(vec![rcx.ty_cx.local_with_repr("".to_string(), ty)],
                Term::Type));

        rcx.ind_hyp = ind_hyp;

        rcx
    }

    fn eta_expand(&self) -> Term {
        let mut pi = self.inductive_ty.ty.clone();
        let mut result = self.inductive_ty.name.to_term();
        let mut i = 0;
        let mut locals = vec![];
        while let Term::Forall { ty, term, .. } = pi {
            let local = self.ty_cx.local_with_repr(format!("x{}", 0), *ty);
            locals.push(local);
            pi = *term;
        }
        Term::abstract_lambda(
            locals.clone(),
            Term::apply_all(result, locals.into_iter().map(|t| t.to_term()).collect()))
    }

    pub fn with_params(&self, term: Term) -> Term {
        let params = self.inductive_ty
                         .parameters
                         .iter()
                         .map(|x| x.to_term())
                         .collect();

        Term::apply_all(term, params).whnf()
    }

    fn is_recursive_arg(&self, term: &Term) -> bool {
        match term.head() {
            None => false,
            Some(h) => h == self.inductive_ty.name.to_term(),
        }
    }

    pub fn minor_premise_for(&mut self, ind_hyp: &Name, ctor: &(Name, Term)) -> Term {
        // Apply the constructor name to the parameters.
        let ctor_with_params =
            self.with_params(ctor.0.to_term());

        // Apply the constructor type to the parameters.
        let mut ctor_ty_with_params =
            self.with_params(ctor.1.clone());

        let mut i = 0;
        let mut binders = Vec::new();
        let mut arguments = Vec::new();
        let mut pi = &ctor_ty_with_params;

        while let &Term::Forall { ref ty, ref term, .. } = pi {
            // Create a local with a fresh name and type of the binder.
            let arg_local =
                self.ty_cx.local_with_repr(
                    format!("a{}", i),
                    *ty.clone());

            // Add this to the list of binders (a0 : A) (a1 : List A)
            binders.push(arg_local.clone());
            // (a0 : A) (a1 : List A) -> C a1 -> C (Cons a0 a1)

            // If this is a recursive argument we all need to generate a piece of proof
            // for that case for example `C a1`.
            if self.is_recursive_arg(&*ty) {
                let local_x =
                    self.ty_cx.local_with_repr(
                        "".to_string(),
                        Term::apply(ind_hyp.to_term(), arg_local.to_term()));

                 arguments.push(local_x);
            }

            pi = &**term;
            i += 1;
        }

        let c_for_ctor = Term::apply(
            ind_hyp.to_term(),
            Term::apply_all(
                ctor_with_params,
                binders.iter()
                       .map(|x| x.to_term())
                       .collect()));

        Term::abstract_pi(
            binders,
            Term::abstract_pi(
                arguments,
                c_for_ctor))
    }
}

/// Construct a recursor for `data_type`.
pub fn make_recursor(ty_cx: &mut TyCtxt, data_type: &Data) {
    let mut rcx = RecursorCx::new(ty_cx, data_type);

    let params = data_type.parameters.clone();

    let ind_hyp = rcx.ind_hyp.clone();

    let mut premises = Vec::new();

    for ctor in &data_type.ctors {
        premises.push(rcx.minor_premise_for(&ind_hyp, ctor))
    }

    let premises: Vec<_> = premises.into_iter()
                                   .map(|p| rcx.ty_cx.local_with_repr("".to_string(), p))
                                   .collect();

    let mut result = data_type.ty.clone();

    let mut tys = Vec::new();
    while let Term::Forall { ty, term, .. } = result {
        tys.push(*ty.clone());
        result = *term;
    }

    tys.push(data_type.name.to_term());

    let tys: Vec<_> = tys.into_iter()
                         .enumerate()
                         .map(|(i, ty)| rcx.ty_cx.local_with_repr(format!("a{}", i), ty))
                         .collect();

    let tys_terms: Vec<_> = tys.iter().map(|t| t.to_term()).collect();

    let recursor_ty =
        Term::abstract_pi(
            params.clone(),
            Term::abstract_pi(vec![ind_hyp.clone()],
                Term::abstract_pi(premises.clone(),
                    Term::abstract_pi(tys.clone(),
                        Term::apply_all(ind_hyp.to_term(),
                        tys_terms.clone())))));

    // println!("declare_datatype: recursor_ty={}", recursor_ty);

    let mut inner_terms = vec![ind_hyp.clone().to_term()];
    inner_terms.extend(premises.clone().into_iter().map(|x| x.to_term()));
    inner_terms.extend(tys_terms.clone().into_iter());

    let recursor_body =
        Term::abstract_lambda(
            params.clone(),
            Term::abstract_lambda(
                vec![ind_hyp.clone()],
                Term::abstract_lambda(
                    premises,
                    Term::abstract_lambda(
                        tys,
                        Term::Recursor(
                            data_type.name.clone(),
                            1,
                            inner_terms)))));

    rcx.ty_cx.definitions.insert(data_type.name.in_scope("rec".to_string()).unwrap(),
                            (recursor_ty, recursor_body));
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match sockets.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr as u64,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => {
                                trace!("New socket added to epoll list");
                                trace!("socket.id: {}", socket.id());
                                trace!("epfd: {}", epfd);
                                trace!("fd: {}", sfd);
                            },
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd to epoll watch list
                            //
                            // Rust's TcpStream clone method makes use of the F_DUPFD flag
                            // for duplicating file descriptors. This means the fd we just read
                            // from and/or the original fd added to epoll for this stream cannot
                            // be used to MOD, or DEL and ADD again, in order to re-register for
                            // the same events, with the same fd.
                            // The originally added fd is essentially invalid at this point, but
                            // lucky for us, Rust sets the CLOEXEC flag for fds, which means that
                            // the system will clean them up when they go out of scope. Also,
                            // epoll removes fds when the system clears them, so we should be OK
                            // from any internal fd leaks here.
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    warn!("Epoll CtrlError during mod: {}", e);
                                    warn!("s.id: {}", s_id);
                                    warn!("epfd: {}", t_epfd.clone());
                                    warn!("fd: {}", socketfd);
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<commit_msg>Eat this, epoll<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match sockets.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr as u64,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => {
                                trace!("New socket added to epoll list");
                                trace!("socket.id: {}", socket.id());
                                trace!("epfd: {}", epfd);
                                trace!("fd: {}", sfd);
                            },
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd to epoll watch list
                            //
                            // Rust's TcpStream clone method makes use of the F_DUPFD flag
                            // for duplicating file descriptors. This means the fd we just read
                            // from and/or the original fd added to epoll for this stream cannot
                            // be used to MOD, or DEL and ADD again, in order to re-register for
                            // the same events, with the same fd.
                            // The originally added fd is essentially invalid at this point, but
                            // lucky for us, Rust sets the CLOEXEC flag for fds, which means that
                            // the system will clean them up when they go out of scope. Also,
                            // epoll removes fds when the system clears them, so we should be OK
                            // from any internal fd leaks here. All we really care about, is if
                            // we receive the EEXIST from the call. In this case, we must apply
                            // the adjustment as a MOD
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    if e == CtlError::EEXIST {
                                        trace!("Fd already exists in epoll, trying ctl::MOD");
                                        match epoll::ctl(t_epfd.clone(), ctl_op::MOD, socketfd,
                                            &mut event) {
                                            Ok(_) => trace!("Socket back in epoll list with mod"),
                                            Err(_) => {
                                                warn!("Error modifying socket in epoll...")
                                            }
                                        };
                                    } else {
                                        warn!("Epoll CtrlError during mod: {}", e);
                                        warn!("s.id: {}", s_id);
                                        warn!("epfd: {}", t_epfd.clone());
                                        warn!("fd: {}", socketfd);
                                    }
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

use ::errors::*;
use ::backend::{
    MidiInputPort as MidiInputPortImpl,
    MidiInput as MidiInputImpl,
    MidiInputConnection as MidiInputConnectionImpl,
    MidiOutputPort as MidiOutputPortImpl,
    MidiOutput as MidiOutputImpl,
    MidiOutputConnection as MidiOutputConnectionImpl
};
use ::Ignore;

/// Trait that abstracts over input and output ports.
pub trait MidiIO {
    /// Type of an input or output port structure.
    type Port: Clone;

    /// Get a collection of all MIDI input or output ports.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it.
    fn ports(&self) -> Vec<Self::Port>;

    /// Get the number of available MIDI input or output ports.
    fn port_count(&self) -> usize;

    /// Get the name of a specified MIDI input or output port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    fn port_name(&self, port: &Self::Port) -> Result<String, PortInfoError>;
}

/// An object representing a single input port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiInput` instance to obtain
/// available ports.
#[derive(Clone, PartialEq)]
pub struct MidiInputPort {
    pub(crate) imp: MidiInputPortImpl
}

/// A collection of input ports.
pub type MidiInputPorts = Vec<MidiInputPort>;

/// An instance of `MidiInput` is required for anything related to MIDI input.
/// Create one with `MidiInput::new`.
pub struct MidiInput {
    //ignore_flags: Ignore
    imp: MidiInputImpl
}

impl MidiInput {
    /// Creates a new `MidiInput` object that is required for any MIDI input functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiInputImpl::new(client_name).map(|imp| MidiInput { imp: imp })
    }

    /// Set flags to decide what kind of messages should be ignored (i.e., filtered out)
    /// by this `MidiInput`. By default, no messages are ignored.
    pub fn ignore(&mut self, flags: Ignore) {
       self.imp.ignore(flags);
    }

    /// Get a collection of all MIDI input ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to receive
    /// MIDI messages.
    pub fn ports(&self) -> MidiInputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI input ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI input port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI input port in order to receive messages.
    /// For each incoming MIDI message, the provided `callback` function will
    /// be called. The first parameter of the callback function is a timestamp
    /// (in microseconds) designating the time since some unspecified point in
    /// the past (which will not change during the lifetime of a
    /// `MidiInputConnection`). The second parameter contains the actual bytes
    /// of the MIDI message.
    ///
    /// Additional data that should be passed whenever the callback is
    /// invoked can be specified by `data`. Use the empty tuple `()` if
    /// you do not want to pass any additional data.
    ///
    /// The connection will be kept open as long as the returned
    /// `MidiInputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect<F, T: Send>(
        self, port: &MidiInputPort, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.connect(&port.imp, port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

impl MidiIO for MidiInput {
    type Port = MidiInputPort;

    fn ports(&self) -> MidiInputPorts {
        self.imp.ports_internal()
    }

    fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }
}

#[cfg(unix)]
impl<T: Send> ::os::unix::VirtualInput<T> for MidiInput {
    fn create_virtual<F>(
        self, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<Self>>
    where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.create_virtual(port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI input port.
pub struct MidiInputConnection<T: 'static> {
    imp: MidiInputConnectionImpl<T>
}

impl<T> MidiInputConnection<T> {
    /// Closes the connection. The returned values allow you to
    /// inspect the additional data passed to the callback (the `data`
    /// parameter of `connect`), or to reuse the `MidiInput` object,
    /// but they can be safely ignored.
    pub fn close(self) -> (MidiInput, T) {
        let (imp, data) = self.imp.close();
        (MidiInput { imp: imp }, data)
    }
}

/// An object representing a single output port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiOutput` instance to obtain
/// available ports.
#[derive(Clone, PartialEq)]
pub struct MidiOutputPort {
    pub(crate) imp: MidiOutputPortImpl
}

/// A collection of output ports.
pub type MidiOutputPorts = Vec<MidiOutputPort>;

/// An instance of `MidiOutput` is required for anything related to MIDI output.
/// Create one with `MidiOutput::new`.
pub struct MidiOutput {
    imp: MidiOutputImpl
}

impl MidiOutput {
    /// Creates a new `MidiOutput` object that is required for any MIDI output functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiOutputImpl::new(client_name).map(|imp| MidiOutput { imp: imp })
    }

    /// Get a collection of all MIDI output ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to send
    /// MIDI messages.
    pub fn ports(&self) -> MidiOutputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI output ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI output port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI output port in order to send messages.
    /// The connection will be kept open as long as the returned
    /// `MidiOutputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect(self, port: &MidiOutputPort, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.connect(&port.imp, port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

impl MidiIO for MidiOutput {
    type Port = MidiOutputPort;

    fn ports(&self) -> MidiOutputPorts {
        self.imp.ports_internal()
    }

    fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }
}

#[cfg(unix)]
impl ::os::unix::VirtualOutput for MidiOutput {
    fn create_virtual(self, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.create_virtual(port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI output port.
pub struct MidiOutputConnection {
   imp: MidiOutputConnectionImpl
}

impl MidiOutputConnection {
    /// Closes the connection. The returned value allows you to
    /// reuse the `MidiOutput` object, but it can be safely ignored.
    pub fn close(self) -> MidiOutput {
        MidiOutput { imp: self.imp.close() }
    }

    /// Send a message to the port that this output connection is connected to.
    /// The message must be a valid MIDI message (see https://www.midi.org/specifications/item/table-1-summary-of-midi-message).
    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        self.imp.send(message)
    }
}

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

    #[test]
    fn test_trait_impls() {
        // make sure that all the structs implement `Send`
        fn is_send<T: Send>() {}
        is_send::<MidiInput>();
        is_send::<MidiOutput>();
        #[cfg(not(target_arch = "wasm32"))] {
            // The story around threading and `Send` on WASM is not clear yet
            // Tracking issue:      https://github.com/Boddlnagg/midir/issues/49
            // Prev. discussion:    https://github.com/Boddlnagg/midir/pull/47
            is_send::<MidiInputPort>();
            is_send::<MidiInputConnection<()>>();
            is_send::<MidiOutputPort>();
            is_send::<MidiOutputConnection>();
        }

        // make sure that Midi port structs implement `PartialEq`
        fn is_partial_eq<T: PartialEq>() {}
        is_partial_eq::<MidiInputPortImpl>();
        is_partial_eq::<MidiOutputPortImpl>();

        is_partial_eq::<MidiInputPort>();
        is_partial_eq::<MidiOutputPort>();
    }
}
<commit_msg>Update MIDI specification link in the documentation<commit_after>#![deny(missing_docs)]

use ::errors::*;
use ::backend::{
    MidiInputPort as MidiInputPortImpl,
    MidiInput as MidiInputImpl,
    MidiInputConnection as MidiInputConnectionImpl,
    MidiOutputPort as MidiOutputPortImpl,
    MidiOutput as MidiOutputImpl,
    MidiOutputConnection as MidiOutputConnectionImpl
};
use ::Ignore;

/// Trait that abstracts over input and output ports.
pub trait MidiIO {
    /// Type of an input or output port structure.
    type Port: Clone;

    /// Get a collection of all MIDI input or output ports.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it.
    fn ports(&self) -> Vec<Self::Port>;

    /// Get the number of available MIDI input or output ports.
    fn port_count(&self) -> usize;

    /// Get the name of a specified MIDI input or output port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    fn port_name(&self, port: &Self::Port) -> Result<String, PortInfoError>;
}

/// An object representing a single input port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiInput` instance to obtain
/// available ports.
#[derive(Clone, PartialEq)]
pub struct MidiInputPort {
    pub(crate) imp: MidiInputPortImpl
}

/// A collection of input ports.
pub type MidiInputPorts = Vec<MidiInputPort>;

/// An instance of `MidiInput` is required for anything related to MIDI input.
/// Create one with `MidiInput::new`.
pub struct MidiInput {
    //ignore_flags: Ignore
    imp: MidiInputImpl
}

impl MidiInput {
    /// Creates a new `MidiInput` object that is required for any MIDI input functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiInputImpl::new(client_name).map(|imp| MidiInput { imp: imp })
    }

    /// Set flags to decide what kind of messages should be ignored (i.e., filtered out)
    /// by this `MidiInput`. By default, no messages are ignored.
    pub fn ignore(&mut self, flags: Ignore) {
       self.imp.ignore(flags);
    }

    /// Get a collection of all MIDI input ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to receive
    /// MIDI messages.
    pub fn ports(&self) -> MidiInputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI input ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI input port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI input port in order to receive messages.
    /// For each incoming MIDI message, the provided `callback` function will
    /// be called. The first parameter of the callback function is a timestamp
    /// (in microseconds) designating the time since some unspecified point in
    /// the past (which will not change during the lifetime of a
    /// `MidiInputConnection`). The second parameter contains the actual bytes
    /// of the MIDI message.
    ///
    /// Additional data that should be passed whenever the callback is
    /// invoked can be specified by `data`. Use the empty tuple `()` if
    /// you do not want to pass any additional data.
    ///
    /// The connection will be kept open as long as the returned
    /// `MidiInputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect<F, T: Send>(
        self, port: &MidiInputPort, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.connect(&port.imp, port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

impl MidiIO for MidiInput {
    type Port = MidiInputPort;

    fn ports(&self) -> MidiInputPorts {
        self.imp.ports_internal()
    }

    fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }
}

#[cfg(unix)]
impl<T: Send> ::os::unix::VirtualInput<T> for MidiInput {
    fn create_virtual<F>(
        self, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<Self>>
    where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.create_virtual(port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI input port.
pub struct MidiInputConnection<T: 'static> {
    imp: MidiInputConnectionImpl<T>
}

impl<T> MidiInputConnection<T> {
    /// Closes the connection. The returned values allow you to
    /// inspect the additional data passed to the callback (the `data`
    /// parameter of `connect`), or to reuse the `MidiInput` object,
    /// but they can be safely ignored.
    pub fn close(self) -> (MidiInput, T) {
        let (imp, data) = self.imp.close();
        (MidiInput { imp: imp }, data)
    }
}

/// An object representing a single output port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiOutput` instance to obtain
/// available ports.
#[derive(Clone, PartialEq)]
pub struct MidiOutputPort {
    pub(crate) imp: MidiOutputPortImpl
}

/// A collection of output ports.
pub type MidiOutputPorts = Vec<MidiOutputPort>;

/// An instance of `MidiOutput` is required for anything related to MIDI output.
/// Create one with `MidiOutput::new`.
pub struct MidiOutput {
    imp: MidiOutputImpl
}

impl MidiOutput {
    /// Creates a new `MidiOutput` object that is required for any MIDI output functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiOutputImpl::new(client_name).map(|imp| MidiOutput { imp: imp })
    }

    /// Get a collection of all MIDI output ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to send
    /// MIDI messages.
    pub fn ports(&self) -> MidiOutputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI output ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI output port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI output port in order to send messages.
    /// The connection will be kept open as long as the returned
    /// `MidiOutputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect(self, port: &MidiOutputPort, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.connect(&port.imp, port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

impl MidiIO for MidiOutput {
    type Port = MidiOutputPort;

    fn ports(&self) -> MidiOutputPorts {
        self.imp.ports_internal()
    }

    fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }
}

#[cfg(unix)]
impl ::os::unix::VirtualOutput for MidiOutput {
    fn create_virtual(self, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.create_virtual(port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI output port.
pub struct MidiOutputConnection {
   imp: MidiOutputConnectionImpl
}

impl MidiOutputConnection {
    /// Closes the connection. The returned value allows you to
    /// reuse the `MidiOutput` object, but it can be safely ignored.
    pub fn close(self) -> MidiOutput {
        MidiOutput { imp: self.imp.close() }
    }

    /// Send a message to the port that this output connection is connected to.
    /// The message must be a valid MIDI message (see https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message).
    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        self.imp.send(message)
    }
}

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

    #[test]
    fn test_trait_impls() {
        // make sure that all the structs implement `Send`
        fn is_send<T: Send>() {}
        is_send::<MidiInput>();
        is_send::<MidiOutput>();
        #[cfg(not(target_arch = "wasm32"))] {
            // The story around threading and `Send` on WASM is not clear yet
            // Tracking issue:      https://github.com/Boddlnagg/midir/issues/49
            // Prev. discussion:    https://github.com/Boddlnagg/midir/pull/47
            is_send::<MidiInputPort>();
            is_send::<MidiInputConnection<()>>();
            is_send::<MidiOutputPort>();
            is_send::<MidiOutputConnection>();
        }

        // make sure that Midi port structs implement `PartialEq`
        fn is_partial_eq<T: PartialEq>() {}
        is_partial_eq::<MidiInputPortImpl>();
        is_partial_eq::<MidiOutputPortImpl>();

        is_partial_eq::<MidiInputPort>();
        is_partial_eq::<MidiOutputPort>();
    }
}
<|endoftext|>


<commit_before>extern crate lazy_static;

use std::env;
use std::io;
use std::path::PathBuf;
use std::fs::{self, DirEntry};
use std::string::String;

pub struct Config {
    pub steps_file: String,
    pub step_implementations_path: PathBuf,
    pub skel_path: PathBuf,
    pub internal_port: String,
}

lazy_static! {
    pub static ref PROJECT_ROOT: PathBuf = PathBuf::from(env_var("GAUGE_PROJECT_ROOT"));
    pub static ref PLUGIN_SOURCE: PathBuf = match env::current_dir() {
        Ok(d) => d,
        Err(_) => PathBuf::from("")
    };

    pub static ref CONFIG: Config = Config {
        steps_file: String::from("steps.rs"),
        step_implementations_path: path_to("tests", &PROJECT_ROOT),
        skel_path: path_to("skel", &PLUGIN_SOURCE),
        internal_port: env_var("GAUGE_INTERNAL_PORT"),
    };
}

pub fn env_var(ev: &'static str) -> String {
    match env::var(ev) {
        Ok(val) => val,
        Err(_) => String::new(),
    }
}

pub fn path_to<'a>(pathslice: &'a str, root: &PathBuf) -> PathBuf { root.join(pathslice) }

pub fn create_dir(dirpath: &PathBuf) -> io::Result<&PathBuf> {
    try!(fs::create_dir_all(dirpath));
    Ok(dirpath)
}

pub fn copy_file<'a>(from: &'a PathBuf, to: &'a PathBuf) -> io::Result<(&'a PathBuf, &'a PathBuf)> {
    try!(fs::copy(from, to));
    Ok((from, to))
}

// Source: https://doc.rust-lang.org/std/fs/fn.read_dir.html
pub fn visit_dirs(dir: &PathBuf, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(visit_dirs(&entry.path(), cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}
<commit_msg>Change usage of io::Result to Result<commit_after>extern crate lazy_static;

use std::env;
use std::io::Result;
use std::path::PathBuf;
use std::fs::{self, DirEntry};
use std::string::String;

pub struct Config {
    pub steps_file: String,
    pub step_implementations_path: PathBuf,
    pub skel_path: PathBuf,
    pub internal_port: String,
}

lazy_static! {
    pub static ref PROJECT_ROOT: PathBuf = PathBuf::from(env_var("GAUGE_PROJECT_ROOT"));
    pub static ref PLUGIN_SOURCE: PathBuf = match env::current_dir() {
        Ok(d) => d,
        Err(_) => PathBuf::from("")
    };

    pub static ref CONFIG: Config = Config {
        steps_file: String::from("steps.rs"),
        step_implementations_path: path_to("tests", &PROJECT_ROOT),
        skel_path: path_to("skel", &PLUGIN_SOURCE),
        internal_port: env_var("GAUGE_INTERNAL_PORT"),
    };
}

pub fn env_var(ev: &'static str) -> String {
    match env::var(ev) {
        Ok(val) => val,
        Err(_) => String::new(),
    }
}

pub fn path_to<'a>(pathslice: &'a str, root: &PathBuf) -> PathBuf { root.join(pathslice) }

pub fn create_dir(dirpath: &PathBuf) -> Result<&PathBuf> {
    try!(fs::create_dir_all(dirpath));
    Ok(dirpath)
}

pub fn copy_file<'a>(from: &'a PathBuf, to: &'a PathBuf) -> Result<(&'a PathBuf, &'a PathBuf)> {
    try!(fs::copy(from, to));
    Ok((from, to))
}

pub fn visit_dirs(dir: &PathBuf, callback: &Fn(&DirEntry)) -> Result<()> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(visit_dirs(&entry.path(), callback));
            } else {
                callback(&entry);
            }
        }
    }
    Ok(())
}
<|endoftext|>