<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use libc;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::hash;
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
use std::string::String;
use translate::*;
use types::{StaticType, Type};

use glib_sys;
use gobject_sys;
use value::{FromValueOptional, SetValue, SetValueOptional, Value};

#[derive(Debug)]
pub struct GString(Inner);

#[derive(Debug)]
enum Inner {
    Native(Option<CString>),
    Foreign(*mut c_char, usize),
}

unsafe impl Send for GString {}
unsafe impl Sync for GString {}

impl GString {
    pub unsafe fn new(ptr: *mut c_char) -> Self {
        assert!(!ptr.is_null());
        GString(Inner::Foreign(ptr, libc::strlen(ptr)))
    }

    pub unsafe fn new_borrowed(ptr: *const c_char) -> Borrowed<Self> {
        assert!(!ptr.is_null());
        Borrowed::new(GString(Inner::Foreign(ptr as *mut _, libc::strlen(ptr))))
    }

    pub fn as_str(&self) -> &str {
        let cstr = match self {
            GString(Inner::Foreign(ptr, length)) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            },
            GString(Inner::Native(cstring)) => cstring
                .as_ref()
                .expect("Native shouldn't be empty")
                .as_c_str(),
        };
        cstr.to_str().unwrap()
    }
}

impl Drop for GString {
    fn drop(&mut self) {
        if let GString(Inner::Foreign(ptr, _len)) = self {
            unsafe {
                glib_sys::g_free(*ptr as *mut _);
            }
        }
    }
}

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

impl hash::Hash for GString {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        let bytes = match self {
            GString(Inner::Foreign(ptr, length)) => unsafe {
                slice::from_raw_parts(*ptr as *const u8, length + 1)
            },
            GString(Inner::Native(cstring)) => cstring
                .as_ref()
                .expect("Native shouldn't be empty")
                .as_bytes(),
        };
        state.write(bytes);
    }
}

impl Borrow<str> for GString {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl Ord for GString {
    fn cmp(&self, other: &GString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

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

impl PartialEq for GString {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for String {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<str> for GString {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl<'a> PartialEq<&'a str> for GString {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl<'a> PartialEq<GString> for &'a str {
    fn eq(&self, other: &GString) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for GString {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for str {
    fn eq(&self, other: &GString) -> bool {
        self == other.as_str()
    }
}

impl PartialOrd<GString> for String {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&String::from(other.as_str())))
    }
}

impl PartialOrd<String> for GString {
    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

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

impl PartialOrd<str> for GString {
    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
        Some(self.as_str().cmp(other))
    }
}

impl Eq for GString {}

impl AsRef<str> for GString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for GString {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(self.as_str())
    }
}

impl Deref for GString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<GString> for String {
    #[inline]
    fn from(mut s: GString) -> Self {
        if let GString(Inner::Native(ref mut cstring)) = s {
            if let Ok(s) = cstring
                .take()
                .expect("Native shouldn't be empty")
                .into_string()
            {
                return s;
            }
        }
        String::from(s.as_str())
    }
}

impl From<GString> for Box<str> {
    #[inline]
    fn from(s: GString) -> Self {
        let st: String = s.into();
        st.into_boxed_str()
    }
}

impl From<String> for GString {
    #[inline]
    fn from(s: String) -> Self {
        s.into_bytes().into()
    }
}

impl From<Box<str>> for GString {
    #[inline]
    fn from(s: Box<str>) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl<'a> From<&'a str> for GString {
    #[inline]
    fn from(s: &'a str) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Vec<u8>> for GString {
    #[inline]
    fn from(s: Vec<u8>) -> Self {
        let cstring = CString::new(s).expect("CString::new failed");
        cstring.into()
    }
}

impl From<CString> for GString {
    #[inline]
    fn from(s: CString) -> Self {
        GString(Inner::Native(Some(s)))
    }
}

impl<'a> From<&'a CStr> for GString {
    #[inline]
    fn from(c: &'a CStr) -> Self {
        CString::from(c).into()
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
        GString::new(ptr as *mut _)
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut u8) -> Self {
        GString::new(ptr as *mut _)
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut i8) -> Self {
        GString::new(ptr as *mut _)
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut u8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut _);
        cstr.into()
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut i8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut _);
        cstr.into()
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *const c_char) -> Borrowed<Self> {
        GString::new_borrowed(ptr)
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed<Self> {
        GString::new_borrowed(ptr as *const c_char)
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed<Self> {
        GString::new_borrowed(ptr as *const c_char)
    }
}

#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
        Stash(self.as_ptr() as *const _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const c_char {
        unsafe {
            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *const c_char
        }
    }
}

#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
        Stash(self.as_ptr() as *mut _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut c_char {
        unsafe {
            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *mut c_char
        }
    }
}

impl GlibPtrDefault for GString {
    type GlibType = *const c_char;
}

impl StaticType for GString {
    fn static_type() -> Type {
        String::static_type()
    }
}

impl StaticType for Vec<GString> {
    fn static_type() -> Type {
        unsafe { from_glib(glib_sys::g_strv_get_type()) }
    }
}

impl<'a> FromValueOptional<'a> for GString {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let val = value.to_glib_none().0;
        if val.is_null() {
            None
        } else {
            let ptr = gobject_sys::g_value_dup_string(val);
            Some(GString::new(ptr))
        }
    }
}

impl SetValue for GString {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl SetValueOptional for GString {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);

#[cfg(test)]
mod tests {
    use glib_sys;
    use gstring::GString;
    use std::ffi::CString;

    #[test]
    fn test_gstring() {
        let data = CString::new("foo").unwrap();
        let ptr = data.as_ptr();

        unsafe {
            let ptr_copy = glib_sys::g_strdup(ptr);
            let gstring = GString::new(ptr_copy);
            assert_eq!(gstring.as_str(), "foo");
            let foo: Box<str> = gstring.into();
            assert_eq!(foo.as_ref(), "foo");
        }
    }

    #[test]
    fn test_owned_glib_string() {
        let data = CString::new("foo").unwrap();
        let ptr = data.as_ptr();
        unsafe {
            let ptr_copy = glib_sys::g_strdup(ptr);
            let gstr = GString::new(ptr_copy);
            assert_eq!(gstr, "foo");
        }
    }

    #[test]
    fn test_gstring_from_str() {
        let gstring: GString = "foo".into();
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_gstring_from_cstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_string_from_gstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let s = String::from(gstring);
        assert_eq!(s, "foo");
    }

    #[test]
    fn test_vec_u8_to_gstring() {
        let v = "foo".as_bytes();
        let s: GString = Vec::from(v).into();
        assert_eq!(s.as_str(), "foo");
    }

    #[test]
    fn test_hashmap() {
        use std::collections::HashMap;

        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let mut h: HashMap<GString, i32> = HashMap::new();
        h.insert(gstring, 42);
        let gstring: GString = "foo".into();
        assert!(h.contains_key(&gstring));
    }
}
<commit_msg>clippy: Permit use of 'foo' as a name<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use libc;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::hash;
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
use std::string::String;
use translate::*;
use types::{StaticType, Type};

use glib_sys;
use gobject_sys;
use value::{FromValueOptional, SetValue, SetValueOptional, Value};

#[derive(Debug)]
pub struct GString(Inner);

#[derive(Debug)]
enum Inner {
    Native(Option<CString>),
    Foreign(*mut c_char, usize),
}

unsafe impl Send for GString {}
unsafe impl Sync for GString {}

impl GString {
    pub unsafe fn new(ptr: *mut c_char) -> Self {
        assert!(!ptr.is_null());
        GString(Inner::Foreign(ptr, libc::strlen(ptr)))
    }

    pub unsafe fn new_borrowed(ptr: *const c_char) -> Borrowed<Self> {
        assert!(!ptr.is_null());
        Borrowed::new(GString(Inner::Foreign(ptr as *mut _, libc::strlen(ptr))))
    }

    pub fn as_str(&self) -> &str {
        let cstr = match self {
            GString(Inner::Foreign(ptr, length)) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            },
            GString(Inner::Native(cstring)) => cstring
                .as_ref()
                .expect("Native shouldn't be empty")
                .as_c_str(),
        };
        cstr.to_str().unwrap()
    }
}

impl Drop for GString {
    fn drop(&mut self) {
        if let GString(Inner::Foreign(ptr, _len)) = self {
            unsafe {
                glib_sys::g_free(*ptr as *mut _);
            }
        }
    }
}

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

impl hash::Hash for GString {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        let bytes = match self {
            GString(Inner::Foreign(ptr, length)) => unsafe {
                slice::from_raw_parts(*ptr as *const u8, length + 1)
            },
            GString(Inner::Native(cstring)) => cstring
                .as_ref()
                .expect("Native shouldn't be empty")
                .as_bytes(),
        };
        state.write(bytes);
    }
}

impl Borrow<str> for GString {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl Ord for GString {
    fn cmp(&self, other: &GString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

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

impl PartialEq for GString {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for String {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<str> for GString {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl<'a> PartialEq<&'a str> for GString {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl<'a> PartialEq<GString> for &'a str {
    fn eq(&self, other: &GString) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for GString {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for str {
    fn eq(&self, other: &GString) -> bool {
        self == other.as_str()
    }
}

impl PartialOrd<GString> for String {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&String::from(other.as_str())))
    }
}

impl PartialOrd<String> for GString {
    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

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

impl PartialOrd<str> for GString {
    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
        Some(self.as_str().cmp(other))
    }
}

impl Eq for GString {}

impl AsRef<str> for GString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for GString {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(self.as_str())
    }
}

impl Deref for GString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<GString> for String {
    #[inline]
    fn from(mut s: GString) -> Self {
        if let GString(Inner::Native(ref mut cstring)) = s {
            if let Ok(s) = cstring
                .take()
                .expect("Native shouldn't be empty")
                .into_string()
            {
                return s;
            }
        }
        String::from(s.as_str())
    }
}

impl From<GString> for Box<str> {
    #[inline]
    fn from(s: GString) -> Self {
        let st: String = s.into();
        st.into_boxed_str()
    }
}

impl From<String> for GString {
    #[inline]
    fn from(s: String) -> Self {
        s.into_bytes().into()
    }
}

impl From<Box<str>> for GString {
    #[inline]
    fn from(s: Box<str>) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl<'a> From<&'a str> for GString {
    #[inline]
    fn from(s: &'a str) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Vec<u8>> for GString {
    #[inline]
    fn from(s: Vec<u8>) -> Self {
        let cstring = CString::new(s).expect("CString::new failed");
        cstring.into()
    }
}

impl From<CString> for GString {
    #[inline]
    fn from(s: CString) -> Self {
        GString(Inner::Native(Some(s)))
    }
}

impl<'a> From<&'a CStr> for GString {
    #[inline]
    fn from(c: &'a CStr) -> Self {
        CString::from(c).into()
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
        GString::new(ptr as *mut _)
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut u8) -> Self {
        GString::new(ptr as *mut _)
    }
}

#[doc(hidden)]
impl FromGlibPtrFull<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut i8) -> Self {
        GString::new(ptr as *mut _)
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut u8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut _);
        cstr.into()
    }
}

#[doc(hidden)]
impl FromGlibPtrNone<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut i8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut _);
        cstr.into()
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *const c_char) -> Borrowed<Self> {
        GString::new_borrowed(ptr)
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed<Self> {
        GString::new_borrowed(ptr as *const c_char)
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed<Self> {
        GString::new_borrowed(ptr as *const c_char)
    }
}

#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
        Stash(self.as_ptr() as *const _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const c_char {
        unsafe {
            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *const c_char
        }
    }
}

#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
        Stash(self.as_ptr() as *mut _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut c_char {
        unsafe {
            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *mut c_char
        }
    }
}

impl GlibPtrDefault for GString {
    type GlibType = *const c_char;
}

impl StaticType for GString {
    fn static_type() -> Type {
        String::static_type()
    }
}

impl StaticType for Vec<GString> {
    fn static_type() -> Type {
        unsafe { from_glib(glib_sys::g_strv_get_type()) }
    }
}

impl<'a> FromValueOptional<'a> for GString {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let val = value.to_glib_none().0;
        if val.is_null() {
            None
        } else {
            let ptr = gobject_sys::g_value_dup_string(val);
            Some(GString::new(ptr))
        }
    }
}

impl SetValue for GString {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl SetValueOptional for GString {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);

#[cfg(test)]
#[allow(clippy::blacklisted_name)]
mod tests {
    use glib_sys;
    use gstring::GString;
    use std::ffi::CString;

    #[test]
    fn test_gstring() {
        let data = CString::new("foo").unwrap();
        let ptr = data.as_ptr();

        unsafe {
            let ptr_copy = glib_sys::g_strdup(ptr);
            let gstring = GString::new(ptr_copy);
            assert_eq!(gstring.as_str(), "foo");
            let foo: Box<str> = gstring.into();
            assert_eq!(foo.as_ref(), "foo");
        }
    }

    #[test]
    fn test_owned_glib_string() {
        let data = CString::new("foo").unwrap();
        let ptr = data.as_ptr();
        unsafe {
            let ptr_copy = glib_sys::g_strdup(ptr);
            let gstr = GString::new(ptr_copy);
            assert_eq!(gstr, "foo");
        }
    }

    #[test]
    fn test_gstring_from_str() {
        let gstring: GString = "foo".into();
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_gstring_from_cstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_string_from_gstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let s = String::from(gstring);
        assert_eq!(s, "foo");
    }

    #[test]
    fn test_vec_u8_to_gstring() {
        let v = "foo".as_bytes();
        let s: GString = Vec::from(v).into();
        assert_eq!(s.as_str(), "foo");
    }

    #[test]
    fn test_hashmap() {
        use std::collections::HashMap;

        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let mut h: HashMap<GString, i32> = HashMap::new();
        h.insert(gstring, 42);
        let gstring: GString = "foo".into();
        assert!(h.contains_key(&gstring));
    }
}
<|endoftext|>


<commit_before>extern crate num;

// the AdditiveIterator trait adds the sum() method to iterators
use std::iter::{AdditiveIterator,count};
// the Integer trait adds the is_odd() method to integer primitives
use num::Integer;

fn main() {
    println!("Find the sum of all the squared odd numbers under 1000");
    let upper: int = 1000;

    // imperative approach
    // declare accumulator variable
    let mut acc = 0;
    // iterate 0, 1, 2, ... to infinity
    for n in count(0, 1) {
        // square the number
        let n_squared = n * n;

        if n_squared >= upper {
            // break loop if exceeded the upper limit
            break;
        } else if n_squared.is_odd() {
            // accumulate value, if it's odd
            acc += n_squared;
        }
    }
    println!("imperative style: {}", acc);

    // functional approach
    let sum_of_squared_odd_numbers =
        // all integers
        count(0, 1).
        // squared
        map(|n| n * n).
        // below upper limit
        take_while(|&n| n < upper).
        // that are odd
        filter(|n| n.is_odd()).
        // sum them
        sum();
    println!("functional style: {}", sum_of_squared_odd_numbers);
}
<commit_msg>Fix #51<commit_after>extern crate num;

// the AdditiveIterator trait adds the sum() method to iterators
use std::iter::{AdditiveIterator,count};
// the Integer trait adds the is_odd() method to integer primitives
use num::Integer;

fn main() {
    println!("Find the sum of all the squared odd numbers under 1000");
    let upper: int = 1000;

    // imperative approach
    // declare accumulator variable
    let mut acc = 0;
    // iterate 0, 1, 2, ... to infinity
    for n in count(0, 1) {
        // square the number
        let n_squared = n * n;

        if n_squared >= upper {
            // break loop if exceeded the upper limit
            break;
        } else if n_squared.is_odd() {
            // accumulate value, if it's odd
            acc += n_squared;
        }
    }
    println!("imperative style: {}", acc);

    // functional approach
    let sum_of_squared_odd_numbers =
        // all natural numbers
        count(0, 1).
        // squared
        map(|n| n * n).
        // below upper limit
        take_while(|&n| n < upper).
        // that are odd
        filter(|n| n.is_odd()).
        // sum them
        sum();
    println!("functional style: {}", sum_of_squared_odd_numbers);
}
<|endoftext|>


<commit_before>use crate::{
    buffer::Buffer, channels::Channels, connection_status::ConnectionState, frames::Frames,
    internal_rpc::InternalRPC, thread::ThreadHandle, waker::Waker, Configuration, ConnectionStatus,
    Error, PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker as MioWaker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection_status: ConnectionStatus,
    configuration: Configuration,
    channels: Channels,
    internal_rpc: InternalRPC,
    frames: Frames,
    connection_io_loop_handle: ThreadHandle,
    waker: Waker,
    socket: T,
    status: Status,
    poll: Poll,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn new(
        connection_status: ConnectionStatus,
        configuration: Configuration,
        channels: Channels,
        internal_rpc: InternalRPC,
        frames: Frames,
        connection_io_loop_handle: ThreadHandle,
        waker: Waker,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        waker.set_waker(MioWaker::new(poll.registry(), WAKER)?);
        let frame_size = std::cmp::max(8192, configuration.frame_max() as usize);
        let mut inner = Self {
            connection_status,
            configuration,
            channels,
            internal_rpc,
            frames,
            connection_io_loop_handle,
            waker,
            socket,
            status: Status::Initial,
            poll,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) {
        if self.status != Status::Setup && self.connection_status.connected() {
            let frame_max = self.configuration.frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.configuration.heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
    }

    fn has_data(&self) -> bool {
        self.frames.has_pending()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection_status.blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        (self.status == Status::Initial
            || self.connection_status.connected()
            || self.connection_status.closing())
            && self.status != Status::Stop
            && !self.connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection_io_loop_handle.clone().register(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serialized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
        );
        waker.wake()
    }

    fn cancel_serialized_frames(&mut self, error: Error) -> Result<()> {
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup();
        self.poll(events)?;
        let res = self.do_run();
        self.internal_rpc.poll(&self.channels).and(res)
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            self.internal_rpc.poll(&self.channels)?;
            if self.connection_status.closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.internal_rpc.poll(&self.channels)?;
            if self.should_heartbeat() {
                self.channels.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection_status.errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let Some(resolver) = self.connection_status.connection_resolver() {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.channels.set_connection_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.socket.flush()?;

        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            }

            self.socket.flush()?;
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection_status.state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer.read_from(&mut self.socket).map(|sz| {
                    trace!("read {} bytes", sz);
                    self.receive_buffer.fill(sz);
                })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.frames.pop(self.channels.flow()) {
            trace!("will write to buffer: {}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.frames.retry((next_msg, resolver));
                            self.send_continue()
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.channels.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.parsing_context()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed);
                Ok(Some(f))
            }
            Err(e) => {
                if !e.is_incomplete() {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<commit_msg>IoLoop: unify error paths<commit_after>use crate::{
    buffer::Buffer, channels::Channels, connection_status::ConnectionState, frames::Frames,
    internal_rpc::InternalRPC, thread::ThreadHandle, waker::Waker, Configuration, ConnectionStatus,
    Error, PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker as MioWaker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection_status: ConnectionStatus,
    configuration: Configuration,
    channels: Channels,
    internal_rpc: InternalRPC,
    frames: Frames,
    connection_io_loop_handle: ThreadHandle,
    waker: Waker,
    socket: T,
    status: Status,
    poll: Poll,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn new(
        connection_status: ConnectionStatus,
        configuration: Configuration,
        channels: Channels,
        internal_rpc: InternalRPC,
        frames: Frames,
        connection_io_loop_handle: ThreadHandle,
        waker: Waker,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        waker.set_waker(MioWaker::new(poll.registry(), WAKER)?);
        let frame_size = std::cmp::max(8192, configuration.frame_max() as usize);
        let mut inner = Self {
            connection_status,
            configuration,
            channels,
            internal_rpc,
            frames,
            connection_io_loop_handle,
            waker,
            socket,
            status: Status::Initial,
            poll,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) {
        if self.status != Status::Setup && self.connection_status.connected() {
            let frame_max = self.configuration.frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.configuration.heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
    }

    fn has_data(&self) -> bool {
        self.frames.has_pending()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection_status.blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        (self.status == Status::Initial
            || self.connection_status.connected()
            || self.connection_status.closing())
            && self.status != Status::Stop
            && !self.connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection_io_loop_handle.clone().register(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.critical_error(err)?;
                        }
                    }
                    Ok(())
                })?,
        );
        waker.wake()
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll_internal_rpc(&self) -> Result<()> {
        self.internal_rpc.poll(&self.channels)
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup();
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection_status.closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.handle_frames()?;
            if self.should_heartbeat() {
                self.channels.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        self.poll_internal_rpc()
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection_status.errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        self.poll_internal_rpc()
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let Some(resolver) = self.connection_status.connection_resolver() {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.channels.set_connection_error(error.clone())?;
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.socket.flush()?;

        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            }

            self.socket.flush()?;
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        self.poll_internal_rpc()
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection_status.state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer.read_from(&mut self.socket).map(|sz| {
                    trace!("read {} bytes", sz);
                    self.receive_buffer.fill(sz);
                })?;
                self.poll_internal_rpc()
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.frames.pop(self.channels.flow()) {
            trace!("will write to buffer: {}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => self.serialized_frames.push_back((sz, resolver)),
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.frames.retry((next_msg, resolver));
                            self.send_continue()?;
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))?;
                        }
                    }
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn handle_frames(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.parse()? {
                self.channels.handle_frame(frame)?;
            }
        }
        self.poll_internal_rpc()
    }

    fn parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.parsing_context()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed);
                Ok(Some(f))
            }
            Err(e) => {
                if !e.is_incomplete() {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<|endoftext|>


<commit_before>/// wrapper for `in` and `out` asm commands.
/// it is `read` and `write` because `in` is a rust keyword.

// FIXME: remake it! Create a `port` struct, which know what should be written and read.

use ::core::marker::PhantomData;

pub struct IOPort<In, Out> {
    num: u16,
    phantom_in: PhantomData<In>,
    phantom_out: PhantomData<Out>,
}

impl<In, Out> IOPort<In, Out> {
    pub const fn new(num: u16) -> Self {
        IOPort { num: num, phantom_in: PhantomData{}, phantom_out: PhantomData{} }
    }
}

pub trait InPort {
    type Type;
    unsafe fn read(&mut self) -> Self::Type;
}

pub trait OutPort {
    type Type;
    unsafe fn write(&mut self, data: Self::Type);
}

impl<Out> InPort for IOPort<u8, Out> {
    type Type = u8;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inb %dx, %al" : "={al}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u8> {
    type Type = u8;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outb %al, %dx" :  : "{al}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

impl<Out> InPort for IOPort<u16, Out> {
    type Type = u16;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u16> {
    type Type = u16;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outw %ax, %dx" :  : "{ax}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

impl<Out> InPort for IOPort<u32, Out> {
    type Type = u32;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inl %dx, %eax" : "={eax}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u32> {
    type Type = u32;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outl %eax, %dx" :  : "{eax}"(data), "{dx}"(self.num) :  : "volatile");
    }
}
<commit_msg>ioports tests added<commit_after>/// wrapper for `in` and `out` asm commands.
/// it is `read` and `write` because `in` is a rust keyword.

use ::core::marker::PhantomData;

pub struct IOPort<In, Out> {
    num: u16,
    phantom_in: PhantomData<In>,
    phantom_out: PhantomData<Out>,
}

impl<In, Out> IOPort<In, Out> {
    pub const fn new(num: u16) -> Self {
        IOPort { num: num, phantom_in: PhantomData{}, phantom_out: PhantomData{} }
    }
}

pub trait InPort {
    type Type;
    unsafe fn read(&mut self) -> Self::Type;
}

pub trait OutPort {
    type Type;
    unsafe fn write(&mut self, data: Self::Type);
}

impl<Out> InPort for IOPort<u8, Out> {
    type Type = u8;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inb %dx, %al" : "={al}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u8> {
    type Type = u8;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outb %al, %dx" :  : "{al}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

impl<Out> InPort for IOPort<u16, Out> {
    type Type = u16;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u16> {
    type Type = u16;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outw %ax, %dx" :  : "{ax}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

impl<Out> InPort for IOPort<u32, Out> {
    type Type = u32;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inl %dx, %eax" : "={eax}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u32> {
    type Type = u32;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outl %eax, %dx" :  : "{eax}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

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

    pub fn test_all() {
        unsafe {
            // Just make an instance. Don't use it;
            let fls = false;
            // volatile to disable optimization
            if ::core::ptr::read_volatile(&fls) {
                let mut port8 = IOPort::<u8, u8>::new(123);
                port8.write(12);
                port8.read();

                let mut port16 = IOPort::<u16, u16>::new(123);
                port16.write(12);
                port16.read();

                let mut port32 = IOPort::<u32, u32>::new(123);
                port32.write(12);
                port32.read();
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Traits, implementations, and macros related to logging timely events.

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;
use std::rc::Rc;

use ::Data;

use timely_communication::Allocate;
use timely_communication;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;
use ::progress::timestamp::Timestamp;

use byteorder::{LittleEndian, WriteBytesExt};

use dataflow::scopes::root::Root;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

use std::io::BufWriter;
use std::net::TcpStream;

use timely_logging;
use timely_logging::Event as LogEvent;
use timely_logging::EventsSetup;
use timely_logging::{CommEvent, CommsSetup};

use timely_communication::Logging;

pub use timely_logging::OperatesEvent;
pub use timely_logging::ChannelsEvent;
pub use timely_logging::ProgressEvent;
pub use timely_logging::MessagesEvent;
pub use timely_logging::ScheduleEvent;
pub use timely_logging::StartStop;
pub use timely_logging::PushProgressEvent;
pub use timely_logging::ApplicationEvent;
pub use timely_logging::GuardedProgressEvent;
pub use timely_logging::GuardedMessageEvent;
pub use timely_logging::CommChannelsEvent;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: ::timely_logging::Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// TODO(andreal)
pub struct TimelyLogger<V: Abomonation> where LogEvent: From<V> {
    stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>,
    _v: ::std::marker::PhantomData<V>,
}

impl<V: Abomonation> TimelyLogger<V> where LogEvent: From<V> {
    fn new(stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>) -> TimelyLogger<V> {
        TimelyLogger {
            stream: stream,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<V: Abomonation> ::timely_logging::Logger for TimelyLogger<V> where timely_logging::Event: From<V> {
    type Record = V;
    fn log(&self, record: V) {
        self.stream.borrow_mut().log(LogEvent::from(record));
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {
    eprintln!("logging: index {}/{}", root.index(), root.peers());
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().setup = Some(EventsSetup {
            index: root.index(),
        });
    });
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().flush();
    });
}

// trait ScheduleLogger {
//     fn contains_active_ops(&self) -> bool;
// }
//
// impl<S: Write> ScheduleLogger for LogEventStream<ScheduleEvent, S> {
//     fn contains_active_ops(&self) -> bool {
//         self.buffer.borrow().iter().any(|&(ref evt, ts) | {
//             match evt.start_stop {
//                 StartStop::Stop { activity } => activity,
//                 _ => false,
//             }
//         })
//     }
// }

struct LogEventStream<S: Copy, E: Clone> {
    setup: Option<S>,
    writer: Option<Box<EventStreamInput<Product<RootTimestamp, u64>, (u64, S, E)>>>,
    _s: ::std::marker::PhantomData<S>,
    _e: ::std::marker::PhantomData<E>,
}

impl<S: Copy, E: Clone> LogEventStream<S, E> {
    fn new() -> Self {
        LogEventStream {
            setup: None,
            writer: None,
            _s: ::std::marker::PhantomData,
            _e: ::std::marker::PhantomData,
        }
    }

    fn flush(&mut self) {
        if let Some(ref mut writer) = self.writer {
            writer.advance_by(RootTimestamp::new(::timely_logging::get_precise_time_ns()));
        }
    }

    fn log(&mut self, record: E) {
        if let Some(ref mut writer) = self.writer {
            writer.send(
                (::timely_logging::get_precise_time_ns(), self.setup.expect("logging not initialized"), record));
        }
    }
}

trait EventStreamInput<T: Timestamp, V: Clone> {
    fn send(&mut self, value: V);
    fn flush(&mut self);
    fn advance_by(&mut self, timestamp: T);
    fn clear(&mut self);
}

/// Logs events to an underlying writer.
pub struct EventStreamWriter<T: Timestamp, V: Clone, P: EventPusher<T, V>> {
    buffer: Vec<V>,
    pusher: P, // RefCell<Option<Box<EventPusher<Product<RootTimestamp, u64>, (u64, S, E)>+Send>>>,
    cur_time: T,
    _v: ::std::marker::PhantomData<V>,
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamWriter<T, V, P> {
    fn new(mut event_pusher: P) -> EventStreamWriter<T, V, P> {
        let cur_time: T = Default::default();
        event_pusher.push(Event::Progress(vec![(cur_time.clone(), 1)]));
        EventStreamWriter {
            buffer: Vec::new(),
            pusher: event_pusher,
            cur_time: cur_time,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamInput<T, V> for EventStreamWriter<T, V, P> {
    fn send(&mut self, value: V) {
        self.buffer.push(value);
    }
    fn flush(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
        }
        self.buffer.clear();
    }
    fn advance_by(&mut self, timestamp: T) {
        assert!(self.cur_time.less_equal(&timestamp));
        self.flush();
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1), (timestamp.clone(), 1)]));
        self.cur_time = timestamp;
    }
    fn clear(&mut self) {
        self.buffer.clear();
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> Drop for EventStreamWriter<T, V, P> {
    fn drop(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
            self.buffer.clear();
        }
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1)]));
    }
}

// /// Special logger for ScheduleEvents
// pub struct ScheduleLogEventStream<S: Write> {
//     logger: LogEventStream<ScheduleEvent, S>,
//     seen_inactive_step: RefCell<bool>,
// }
//
// impl<S: Write> ScheduleLogEventStream<S> {
//     fn new() -> ScheduleLogEventStream<S> {
//         ScheduleLogEventStream {
//             logger: LogEventStream::new(),
//             seen_inactive_step: RefCell::new(false),
//         }
//     }
//
//     fn set(&self, stream: S) {
//         self.logger.set(stream)
//     }
//
//     fn flush_forced(&self) {
//         self.flush();
//         *self.seen_inactive_step.borrow_mut() = false;
//     }
//
//     fn flush_maybe(&self) {
//         if self.logger.contains_active_ops() {
//             self.flush_forced();
//             return;
//         }
//         if !*self.seen_inactive_step.borrow() {
//             self.flush_forced();
//             *self.seen_inactive_step.borrow_mut() = true
//         } else {
//             self.logger.clear();
//         }
//
//     }
// }
//
// impl<S: Write> Logger for ScheduleLogEventStream<S> {
//     type Record = ScheduleEvent;
//     fn log(&self, record: Self::Record) {
//         self.logger.log(record)
//     }
//     fn flush(&self) {
//         self.logger.flush()
//     }
//     // fn record_count(&self) -> usize {
//     //     self.logger.record_count()
//     // }
//     // fn clear(&self) {
//     //     self.logger.clear()
//     // }
//
// }

/// TODO(andreal)
pub fn blackhole() -> Logging {
    Logging::new(
        None,
        Box::new(move || {
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = None;
            });
        }))
}

/// TODO(andreal)
pub fn to_tcp_socket() -> Logging {
    ::timely_logging::initialize_precise_time_ns();
    let target: String = ::std::env::var("TIMELY_LOG_TARGET").expect("no $TIMELY_LOG_TARGET, e.g. 127.0.0.1:34254");
    let comm_target = ::std::env::var("TIMELY_COMM_LOG_TARGET").expect("no $TIMELY_COMM_LOG_TARGET, e.g. 127.0.0.1:34254");
    let (comms_snd, comms_rcv) = ::std::sync::mpsc::channel();

    // comms
    let comm_writer = BufWriter::with_capacity(4096,
        TcpStream::connect(comm_target).expect("failed to connect to logging destination"));
    let comm_thread = ::std::thread::spawn(move || {
        let mut writer = EventStreamWriter::new(EventWriter::new(comm_writer));
        let mut cur_time = timely_logging::get_precise_time_ns();
        writer.advance_by(RootTimestamp::new(cur_time));

        let mut receiver = comms_rcv;
        loop {
            let mut new_time = timely_logging::get_precise_time_ns();
            while let Some((ts, setup, event)) = match receiver.try_recv() {
                Ok(msg) => {
                    Some(msg)
                },
                Err(::std::sync::mpsc::TryRecvError::Empty) => None,
                Err(::std::sync::mpsc::TryRecvError::Disconnected) => return,
            } {
                writer.send((ts, setup, event));
            }
            writer.flush();
            writer.advance_by(RootTimestamp::new(new_time));
            cur_time = new_time;
        }
    });

    Logging::new(
        Some(comms_snd),
        Box::new(move || {
            // timely
            let socket = BufWriter::with_capacity(4096,
                TcpStream::connect(&target).expect("failed to connect to logging destination"));
            let mut timely_writer = EventStreamWriter::new(EventWriter::new(socket));
            timely_writer.advance_by(RootTimestamp::new(timely_logging::get_precise_time_ns()));
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = Some(Box::new(timely_writer));
            });
        }))
}

thread_local!{
    /// TODO(andreal)
    static LOG_EVENT_STREAM: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>> = Rc::new(RefCell::new(LogEventStream::new()));
    /// TODO(andreal)
    /// Logs operator creation.
    pub static OPERATES: TimelyLogger<OperatesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs channel creation.
    pub static CHANNELS: TimelyLogger<ChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs progress transmission.
    pub static PROGRESS: TimelyLogger<ProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs message transmission.
    pub static MESSAGES: TimelyLogger<MessagesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs operator scheduling.
    pub static SCHEDULE: TimelyLogger<ScheduleEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of message to an operator input.
    pub static GUARDED_MESSAGE: TimelyLogger<GuardedMessageEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of notification to an operator.
    pub static GUARDED_PROGRESS: TimelyLogger<GuardedProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs push_external_progress() calls for each operator
    pub static PUSH_PROGRESS: TimelyLogger<PushProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static APPLICATION: TimelyLogger<ApplicationEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static COMM_CHANNELS: TimelyLogger<CommChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
}
<commit_msg>explain dropping the to_tcp_socket communication logging thread<commit_after>//! Traits, implementations, and macros related to logging timely events.

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;
use std::rc::Rc;

use ::Data;

use timely_communication::Allocate;
use timely_communication;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;
use ::progress::timestamp::Timestamp;

use byteorder::{LittleEndian, WriteBytesExt};

use dataflow::scopes::root::Root;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

use std::io::BufWriter;
use std::net::TcpStream;

use timely_logging;
use timely_logging::Event as LogEvent;
use timely_logging::EventsSetup;
use timely_logging::{CommEvent, CommsSetup};

use timely_communication::Logging;

pub use timely_logging::OperatesEvent;
pub use timely_logging::ChannelsEvent;
pub use timely_logging::ProgressEvent;
pub use timely_logging::MessagesEvent;
pub use timely_logging::ScheduleEvent;
pub use timely_logging::StartStop;
pub use timely_logging::PushProgressEvent;
pub use timely_logging::ApplicationEvent;
pub use timely_logging::GuardedProgressEvent;
pub use timely_logging::GuardedMessageEvent;
pub use timely_logging::CommChannelsEvent;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: ::timely_logging::Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// TODO(andreal)
pub struct TimelyLogger<V: Abomonation> where LogEvent: From<V> {
    stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>,
    _v: ::std::marker::PhantomData<V>,
}

impl<V: Abomonation> TimelyLogger<V> where LogEvent: From<V> {
    fn new(stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>) -> TimelyLogger<V> {
        TimelyLogger {
            stream: stream,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<V: Abomonation> ::timely_logging::Logger for TimelyLogger<V> where timely_logging::Event: From<V> {
    type Record = V;
    fn log(&self, record: V) {
        self.stream.borrow_mut().log(LogEvent::from(record));
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {
    eprintln!("logging: index {}/{}", root.index(), root.peers());
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().setup = Some(EventsSetup {
            index: root.index(),
        });
    });
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().flush();
    });
}

// trait ScheduleLogger {
//     fn contains_active_ops(&self) -> bool;
// }
//
// impl<S: Write> ScheduleLogger for LogEventStream<ScheduleEvent, S> {
//     fn contains_active_ops(&self) -> bool {
//         self.buffer.borrow().iter().any(|&(ref evt, ts) | {
//             match evt.start_stop {
//                 StartStop::Stop { activity } => activity,
//                 _ => false,
//             }
//         })
//     }
// }

struct LogEventStream<S: Copy, E: Clone> {
    setup: Option<S>,
    writer: Option<Box<EventStreamInput<Product<RootTimestamp, u64>, (u64, S, E)>>>,
    _s: ::std::marker::PhantomData<S>,
    _e: ::std::marker::PhantomData<E>,
}

impl<S: Copy, E: Clone> LogEventStream<S, E> {
    fn new() -> Self {
        LogEventStream {
            setup: None,
            writer: None,
            _s: ::std::marker::PhantomData,
            _e: ::std::marker::PhantomData,
        }
    }

    fn flush(&mut self) {
        if let Some(ref mut writer) = self.writer {
            writer.advance_by(RootTimestamp::new(::timely_logging::get_precise_time_ns()));
        }
    }

    fn log(&mut self, record: E) {
        if let Some(ref mut writer) = self.writer {
            writer.send(
                (::timely_logging::get_precise_time_ns(), self.setup.expect("logging not initialized"), record));
        }
    }
}

trait EventStreamInput<T: Timestamp, V: Clone> {
    fn send(&mut self, value: V);
    fn flush(&mut self);
    fn advance_by(&mut self, timestamp: T);
    fn clear(&mut self);
}

/// Logs events to an underlying writer.
pub struct EventStreamWriter<T: Timestamp, V: Clone, P: EventPusher<T, V>> {
    buffer: Vec<V>,
    pusher: P, // RefCell<Option<Box<EventPusher<Product<RootTimestamp, u64>, (u64, S, E)>+Send>>>,
    cur_time: T,
    _v: ::std::marker::PhantomData<V>,
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamWriter<T, V, P> {
    fn new(mut event_pusher: P) -> EventStreamWriter<T, V, P> {
        let cur_time: T = Default::default();
        event_pusher.push(Event::Progress(vec![(cur_time.clone(), 1)]));
        EventStreamWriter {
            buffer: Vec::new(),
            pusher: event_pusher,
            cur_time: cur_time,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamInput<T, V> for EventStreamWriter<T, V, P> {
    fn send(&mut self, value: V) {
        self.buffer.push(value);
    }
    fn flush(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
        }
        self.buffer.clear();
    }
    fn advance_by(&mut self, timestamp: T) {
        assert!(self.cur_time.less_equal(&timestamp));
        self.flush();
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1), (timestamp.clone(), 1)]));
        self.cur_time = timestamp;
    }
    fn clear(&mut self) {
        self.buffer.clear();
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> Drop for EventStreamWriter<T, V, P> {
    fn drop(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
            self.buffer.clear();
        }
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1)]));
    }
}

// /// Special logger for ScheduleEvents
// pub struct ScheduleLogEventStream<S: Write> {
//     logger: LogEventStream<ScheduleEvent, S>,
//     seen_inactive_step: RefCell<bool>,
// }
//
// impl<S: Write> ScheduleLogEventStream<S> {
//     fn new() -> ScheduleLogEventStream<S> {
//         ScheduleLogEventStream {
//             logger: LogEventStream::new(),
//             seen_inactive_step: RefCell::new(false),
//         }
//     }
//
//     fn set(&self, stream: S) {
//         self.logger.set(stream)
//     }
//
//     fn flush_forced(&self) {
//         self.flush();
//         *self.seen_inactive_step.borrow_mut() = false;
//     }
//
//     fn flush_maybe(&self) {
//         if self.logger.contains_active_ops() {
//             self.flush_forced();
//             return;
//         }
//         if !*self.seen_inactive_step.borrow() {
//             self.flush_forced();
//             *self.seen_inactive_step.borrow_mut() = true
//         } else {
//             self.logger.clear();
//         }
//
//     }
// }
//
// impl<S: Write> Logger for ScheduleLogEventStream<S> {
//     type Record = ScheduleEvent;
//     fn log(&self, record: Self::Record) {
//         self.logger.log(record)
//     }
//     fn flush(&self) {
//         self.logger.flush()
//     }
//     // fn record_count(&self) -> usize {
//     //     self.logger.record_count()
//     // }
//     // fn clear(&self) {
//     //     self.logger.clear()
//     // }
//
// }

/// TODO(andreal)
pub fn blackhole() -> Logging {
    Logging::new(
        None,
        Box::new(move || {
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = None;
            });
        }))
}

/// TODO(andreal)
pub fn to_tcp_socket() -> Logging {
    ::timely_logging::initialize_precise_time_ns();
    let target: String = ::std::env::var("TIMELY_LOG_TARGET").expect("no $TIMELY_LOG_TARGET, e.g. 127.0.0.1:34254");
    let comm_target = ::std::env::var("TIMELY_COMM_LOG_TARGET").expect("no $TIMELY_COMM_LOG_TARGET, e.g. 127.0.0.1:34254");
    let (comms_snd, comms_rcv) = ::std::sync::mpsc::channel();

    // comms
    let comm_writer = BufWriter::with_capacity(4096,
        TcpStream::connect(comm_target).expect("failed to connect to logging destination"));
    /* thread is detached */ ::std::thread::spawn(move || {
        let mut writer = EventStreamWriter::new(EventWriter::new(comm_writer));
        let mut cur_time = timely_logging::get_precise_time_ns();
        writer.advance_by(RootTimestamp::new(cur_time));

        let mut receiver = comms_rcv;
        loop {
            let mut new_time = timely_logging::get_precise_time_ns();
            while let Some((ts, setup, event)) = match receiver.try_recv() {
                Ok(msg) => {
                    Some(msg)
                },
                Err(::std::sync::mpsc::TryRecvError::Empty) => None,
                Err(::std::sync::mpsc::TryRecvError::Disconnected) => return,
            } {
                writer.send((ts, setup, event));
            }
            writer.flush();
            writer.advance_by(RootTimestamp::new(new_time));
            cur_time = new_time;
        }
    });

    Logging::new(
        Some(comms_snd),
        Box::new(move || {
            // timely
            let socket = BufWriter::with_capacity(4096,
                TcpStream::connect(&target).expect("failed to connect to logging destination"));
            let mut timely_writer = EventStreamWriter::new(EventWriter::new(socket));
            timely_writer.advance_by(RootTimestamp::new(timely_logging::get_precise_time_ns()));
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = Some(Box::new(timely_writer));
            });
        }))
}

thread_local!{
    /// TODO(andreal)
    static LOG_EVENT_STREAM: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>> = Rc::new(RefCell::new(LogEventStream::new()));
    /// TODO(andreal)
    /// Logs operator creation.
    pub static OPERATES: TimelyLogger<OperatesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs channel creation.
    pub static CHANNELS: TimelyLogger<ChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs progress transmission.
    pub static PROGRESS: TimelyLogger<ProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs message transmission.
    pub static MESSAGES: TimelyLogger<MessagesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs operator scheduling.
    pub static SCHEDULE: TimelyLogger<ScheduleEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of message to an operator input.
    pub static GUARDED_MESSAGE: TimelyLogger<GuardedMessageEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of notification to an operator.
    pub static GUARDED_PROGRESS: TimelyLogger<GuardedProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs push_external_progress() calls for each operator
    pub static PUSH_PROGRESS: TimelyLogger<PushProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static APPLICATION: TimelyLogger<ApplicationEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static COMM_CHANNELS: TimelyLogger<CommChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
}
<|endoftext|>