<commit_before>use std::cmp::Ordering;

use kstring::KStringCow;

use crate::DisplayCow;
use crate::State;
use crate::{Array, ArrayView, Object, ObjectView};
use crate::{Scalar, ScalarCow};
use crate::{ValueCow, ValueView, ValueViewCmp};

/// An enum to represent different value types
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
    /// A scalar value.
    Scalar(Scalar),
    /// A sequence of `Value`s.
    Array(Array),
    /// A sequence of key/`Value` pairs.
    Object(Object),
    /// Query symbol.
    State(State),
    /// Nothing.
    Nil,
}

impl Value {
    /// Create as a `Scalar`.
    pub fn scalar<T: Into<Scalar>>(value: T) -> Self {
        Value::Scalar(ScalarCow::new(value))
    }

    /// Create as an `Array`.
    pub fn array<I: IntoIterator<Item = Value>>(iter: I) -> Value {
        let v: Array = iter.into_iter().collect();
        Value::Array(v)
    }

    /// Performs the conversion.
    pub fn as_view(&self) -> &dyn ValueView {
        match &self {
            Value::Scalar(ref x) => x,
            Value::Object(ref x) => x,
            Value::Array(ref x) => x,
            Value::State(ref x) => x,
            Value::Nil => self,
        }
    }

    /// Extracts the scalar value if it is a scalar.
    pub fn into_scalar(self) -> Option<Scalar> {
        match self {
            Value::Scalar(s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn into_array(self) -> Option<Array> {
        match self {
            Value::Array(s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value as mutable if it is a object.
    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
        match *self {
            Value::Array(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value if it is a object.
    pub fn into_object(self) -> Option<Object> {
        match self {
            Value::Object(s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value as mutable if it is a object.
    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
        match *self {
            Value::Object(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the state if it is one
    pub fn into_state(self) -> Option<State> {
        match self {
            Value::State(s) => Some(s),
            _ => None,
        }
    }
}

impl ValueView for Value {
    fn render(&self) -> DisplayCow<'_> {
        match *self {
            Value::Scalar(ref x) => x.render(),
            Value::Array(ref x) => x.render(),
            Value::Object(ref x) => x.render(),
            Value::State(ref x) => x.render(),
            Value::Nil => DisplayCow::Borrowed(&""),
        }
    }
    fn source(&self) -> DisplayCow<'_> {
        match *self {
            Value::Scalar(ref x) => x.source(),
            Value::Array(ref x) => x.source(),
            Value::Object(ref x) => x.source(),
            Value::State(ref x) => x.source(),
            Value::Nil => DisplayCow::Owned(Box::new(crate::StrDisplay {
                s: self.type_name(),
            })),
        }
    }
    fn type_name(&self) -> &'static str {
        match *self {
            Value::Scalar(ref x) => x.type_name(),
            Value::Array(ref x) => x.type_name(),
            Value::Object(ref x) => x.type_name(),
            Value::State(ref x) => x.type_name(),
            Value::Nil => "nil",
        }
    }
    fn query_state(&self, state: State) -> bool {
        match *self {
            Value::Scalar(ref x) => x.query_state(state),
            Value::Array(ref x) => x.query_state(state),
            Value::Object(ref x) => x.query_state(state),
            Value::State(ref x) => x.query_state(state),
            Value::Nil => match state {
                State::Truthy => false,
                State::DefaultValue => true,
                State::Empty => true,
                State::Blank => true,
            },
        }
    }

    fn to_kstr(&self) -> KStringCow<'_> {
        match *self {
            Value::Scalar(ref x) => x.to_kstr(),
            Value::Array(ref x) => x.to_kstr(),
            Value::Object(ref x) => x.to_kstr(),
            Value::State(ref x) => x.to_kstr(),
            Value::Nil => KStringCow::from_static(""),
        }
    }
    fn to_value(&self) -> Value {
        match self {
            Value::Scalar(ref x) => {
                let x = x.clone();
                let x = x.into_owned();
                Value::Scalar(x)
            }
            Value::Array(ref x) => Value::Array(x.clone()),
            Value::Object(ref x) => Value::Object(x.clone()),
            Value::State(ref x) => Value::State(*x),
            Value::Nil => Value::Nil,
        }
    }

    fn as_scalar(&self) -> Option<ScalarCow<'_>> {
        match self {
            Value::Scalar(s) => Some(s.as_ref()),
            _ => None,
        }
    }
    fn as_array(&self) -> Option<&dyn ArrayView> {
        match self {
            Value::Array(ref s) => Some(s),
            _ => None,
        }
    }
    fn as_object(&self) -> Option<&dyn ObjectView> {
        match self {
            Value::Object(ref s) => Some(s),
            _ => None,
        }
    }
    fn as_state(&self) -> Option<State> {
        match self {
            Value::State(s) => Some(*s),
            _ => None,
        }
    }
    fn is_nil(&self) -> bool {
        match self {
            Value::Nil => true,
            _ => false,
        }
    }
}

impl From<Scalar> for Value {
    fn from(other: Scalar) -> Self {
        Value::Scalar(other)
    }
}

impl From<Array> for Value {
    fn from(other: Array) -> Self {
        Value::Array(other)
    }
}

impl From<Object> for Value {
    fn from(other: Object) -> Self {
        Value::Object(other)
    }
}

impl From<State> for Value {
    fn from(other: State) -> Self {
        Value::State(other)
    }
}

/// Iterator over a `Value`s keys.
#[derive(Debug)]
pub struct Keys<'s>(::std::vec::IntoIter<ScalarCow<'s>>);

impl<'s> Iterator for Keys<'s> {
    type Item = ScalarCow<'s>;

    #[inline]
    fn next(&mut self) -> Option<ScalarCow<'s>> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.0.count()
    }
}

impl<'s> ExactSizeIterator for Keys<'s> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for Value {
    fn default() -> Self {
        Self::Nil
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Self) -> bool {
        crate::value_eq(self, other)
    }
}

impl<'v> PartialEq<ValueViewCmp<'v>> for Value {
    fn eq(&self, other: &ValueViewCmp<'v>) -> bool {
        ValueViewCmp::new(self) == *other
    }
}

impl<'v> PartialEq<ValueCow<'v>> for Value {
    fn eq(&self, other: &ValueCow<'v>) -> bool {
        crate::value_eq(self.as_view(), other.as_view())
    }
}

impl PartialEq<i32> for Value {
    fn eq(&self, other: &i32) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<f64> for Value {
    fn eq(&self, other: &f64) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<bool> for Value {
    fn eq(&self, other: &bool) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<crate::DateTime> for Value {
    fn eq(&self, other: &crate::DateTime) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<crate::Date> for Value {
    fn eq(&self, other: &crate::Date) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<str> for Value {
    fn eq(&self, other: &str) -> bool {
        let other = KStringCow::from_ref(other);
        crate::value_eq(self, &other)
    }
}

impl<'s> PartialEq<&'s str> for Value {
    fn eq(&self, other: &&str) -> bool {
        crate::value_eq(self, other)
    }
}

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

impl PartialEq<kstring::KString> for Value {
    fn eq(&self, other: &kstring::KString) -> bool {
        crate::value_eq(self, &other.as_ref())
    }
}

impl<'s> PartialEq<kstring::KStringRef<'s>> for Value {
    fn eq(&self, other: &kstring::KStringRef<'s>) -> bool {
        crate::value_eq(self, other)
    }
}

impl<'s> PartialEq<kstring::KStringCow<'s>> for Value {
    fn eq(&self, other: &kstring::KStringCow<'s>) -> bool {
        crate::value_eq(self, other)
    }
}

impl Eq for Value {}

impl PartialOrd<Value> for Value {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        crate::value_cmp(self, other)
    }
}

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

    #[test]
    fn test_to_string_scalar() {
        let val = Value::scalar(42f64);
        assert_eq!(&val.render().to_string(), "42");
        assert_eq!(&val.to_kstr(), "42");
    }

    #[test]
    fn test_to_string_array() {
        let val = Value::Array(vec![
            Value::scalar(3f64),
            Value::scalar("test"),
            Value::scalar(5.3),
        ]);
        assert_eq!(&val.render().to_string(), "3test5.3");
        assert_eq!(&val.to_kstr(), "3test5.3");
    }

    // TODO make a test for object, remember values are in arbitrary orders in HashMaps

    #[test]
    fn test_to_string_nil() {
        assert_eq!(&Value::Nil.render().to_string(), "");
        assert_eq!(&Value::Nil.to_kstr(), "");
    }

    #[test]
    fn scalar_equality() {
        assert_eq!(Value::scalar("alpha"), Value::scalar("alpha"));
        assert_eq!(Value::scalar(""), Value::scalar(""));
        assert!(Value::scalar("alpha") != Value::scalar("beta"));
        assert!(Value::scalar("beta") != Value::scalar("alpha"));
    }

    #[test]
    fn scalars_have_ruby_truthiness() {
        // all strings in ruby are true
        assert_eq!(Value::scalar(true), Value::scalar("All strings are truthy"));
        assert_eq!(Value::scalar(true), Value::scalar(""));
        assert!(Value::scalar("").query_state(State::Truthy));

        assert_eq!(Value::scalar(true), Value::scalar(true));
        assert!(Value::scalar(true) != Value::scalar(false));
    }

    #[test]
    fn array_equality() {
        let a = Value::Array(vec![Value::scalar("one"), Value::scalar("two")]);
        let b = Value::Array(vec![Value::scalar("alpha"), Value::scalar("beta")]);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn arrays_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Array(Vec::new()));
        assert!(Value::Array(Vec::new()).query_state(State::Truthy));
    }

    #[test]
    fn object_equality() {
        let a: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
        ]
        .iter()
        .cloned()
        .collect();
        let a = Value::Object(a);

        let b: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
            ("gamma".into(), Value::Array(vec![])),
        ]
        .iter()
        .cloned()
        .collect();
        let b = Value::Object(b);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn objects_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Object(Object::new()));
        assert!(Value::Object(Object::new()).query_state(State::Truthy));
    }

    #[test]
    fn nil_equality() {
        assert_eq!(Value::Nil, Value::Nil);
    }

    #[test]
    fn nils_have_ruby_truthiness() {
        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(!Value::Nil.query_state(State::Truthy));

        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(Value::scalar(true) != Value::Nil);
        assert!(Value::scalar("") != Value::Nil);
    }

    #[test]
    fn empty_equality() {
        let blank = Value::State(State::Blank);
        let empty = Value::State(State::Empty);
        // Truth table from https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
        assert_eq!(empty, empty);
        assert_eq!(empty, blank);
        assert_eq!(empty, value!(""));
        assert_ne!(empty, value!(" "));
        assert_eq!(empty, value!([]));
        assert_ne!(empty, value!([nil]));
        assert_eq!(empty, value!({}));
        assert_ne!(empty, value!({ "a": nil }));
    }

    #[test]
    fn blank_equality() {
        let blank = Value::State(State::Blank);
        let empty = Value::State(State::Empty);
        // Truth table from https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
        assert_eq!(blank, blank);
        assert_eq!(blank, empty);
        assert_eq!(blank, value!(nil));
        assert_eq!(blank, value!(false));
        assert_ne!(blank, value!(true));
        assert_ne!(blank, value!(0));
        assert_ne!(blank, value!(1));
        assert_eq!(blank, value!(""));
        assert_eq!(blank, value!(" "));
        assert_eq!(blank, value!([]));
        assert_ne!(blank, value!([nil]));
        assert_eq!(blank, value!({}));
        assert_ne!(blank, value!({ "a": nil }));
    }
}
<commit_msg>perf(value): Reduce enum dispatch overhead<commit_after>use std::cmp::Ordering;

use kstring::KStringCow;

use crate::DisplayCow;
use crate::State;
use crate::{Array, ArrayView, Object, ObjectView};
use crate::{Scalar, ScalarCow};
use crate::{ValueCow, ValueView, ValueViewCmp};

/// An enum to represent different value types
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
    /// A scalar value.
    Scalar(Scalar),
    /// A sequence of `Value`s.
    Array(Array),
    /// A sequence of key/`Value` pairs.
    Object(Object),
    /// Query symbol.
    State(State),
    /// Nothing.
    Nil,
}

impl Value {
    /// Create as a `Scalar`.
    pub fn scalar<T: Into<Scalar>>(value: T) -> Self {
        Value::Scalar(ScalarCow::new(value))
    }

    /// Create as an `Array`.
    pub fn array<I: IntoIterator<Item = Value>>(iter: I) -> Value {
        let v: Array = iter.into_iter().collect();
        Value::Array(v)
    }

    /// Performs the conversion.
    pub fn as_view(&self) -> &dyn ValueView {
        match &self {
            Value::Scalar(ref x) => x,
            Value::Object(ref x) => x,
            Value::Array(ref x) => x,
            Value::State(ref x) => x,
            Value::Nil => self,
        }
    }

    /// Extracts the scalar value if it is a scalar.
    pub fn into_scalar(self) -> Option<Scalar> {
        match self {
            Value::Scalar(s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn into_array(self) -> Option<Array> {
        match self {
            Value::Array(s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value as mutable if it is a object.
    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
        match *self {
            Value::Array(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value if it is a object.
    pub fn into_object(self) -> Option<Object> {
        match self {
            Value::Object(s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value as mutable if it is a object.
    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
        match *self {
            Value::Object(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the state if it is one
    pub fn into_state(self) -> Option<State> {
        match self {
            Value::State(s) => Some(s),
            _ => None,
        }
    }
}

impl ValueView for Value {
    fn render(&self) -> DisplayCow<'_> {
        match *self {
            Value::Scalar(ref x) => x.render(),
            Value::Array(ref x) => x.render(),
            Value::Object(ref x) => x.render(),
            Value::State(ref x) => x.render(),
            Value::Nil => DisplayCow::Borrowed(&""),
        }
    }
    fn source(&self) -> DisplayCow<'_> {
        match *self {
            Value::Scalar(ref x) => x.source(),
            Value::Array(ref x) => x.source(),
            Value::Object(ref x) => x.source(),
            Value::State(ref x) => x.source(),
            Value::Nil => DisplayCow::Owned(Box::new(crate::StrDisplay {
                s: self.type_name(),
            })),
        }
    }
    fn type_name(&self) -> &'static str {
        match *self {
            Value::Scalar(ref x) => x.type_name(),
            Value::Array(ref x) => x.type_name(),
            Value::Object(ref x) => x.type_name(),
            Value::State(ref x) => x.type_name(),
            Value::Nil => "nil",
        }
    }
    fn query_state(&self, state: State) -> bool {
        match *self {
            Value::Scalar(ref x) => x.query_state(state),
            Value::Array(ref x) => x.query_state(state),
            Value::Object(ref x) => x.query_state(state),
            Value::State(ref x) => x.query_state(state),
            Value::Nil => match state {
                State::Truthy => false,
                State::DefaultValue => true,
                State::Empty => true,
                State::Blank => true,
            },
        }
    }

    fn to_kstr(&self) -> KStringCow<'_> {
        match *self {
            Value::Scalar(ref x) => x.to_kstr(),
            Value::Array(ref x) => x.to_kstr(),
            Value::Object(ref x) => x.to_kstr(),
            Value::State(ref x) => x.to_kstr(),
            Value::Nil => KStringCow::from_static(""),
        }
    }
    fn to_value(&self) -> Value {
        match self {
            Value::Scalar(ref x) => {
                let x = x.clone();
                let x = x.into_owned();
                Value::Scalar(x)
            }
            Value::Array(ref x) => Value::Array(x.clone()),
            Value::Object(ref x) => Value::Object(x.clone()),
            Value::State(ref x) => Value::State(*x),
            Value::Nil => Value::Nil,
        }
    }

    fn as_scalar(&self) -> Option<ScalarCow<'_>> {
        match self {
            Value::Scalar(s) => Some(s.as_ref()),
            _ => None,
        }
    }
    fn as_array(&self) -> Option<&dyn ArrayView> {
        match self {
            Value::Array(ref s) => Some(s),
            _ => None,
        }
    }
    fn as_object(&self) -> Option<&dyn ObjectView> {
        match self {
            Value::Object(ref s) => Some(s),
            _ => None,
        }
    }
    fn as_state(&self) -> Option<State> {
        match self {
            Value::State(s) => Some(*s),
            _ => None,
        }
    }
    fn is_nil(&self) -> bool {
        match self {
            Value::Nil => true,
            _ => false,
        }
    }
}

impl From<Scalar> for Value {
    fn from(other: Scalar) -> Self {
        Value::Scalar(other)
    }
}

impl From<Array> for Value {
    fn from(other: Array) -> Self {
        Value::Array(other)
    }
}

impl From<Object> for Value {
    fn from(other: Object) -> Self {
        Value::Object(other)
    }
}

impl From<State> for Value {
    fn from(other: State) -> Self {
        Value::State(other)
    }
}

/// Iterator over a `Value`s keys.
#[derive(Debug)]
pub struct Keys<'s>(::std::vec::IntoIter<ScalarCow<'s>>);

impl<'s> Iterator for Keys<'s> {
    type Item = ScalarCow<'s>;

    #[inline]
    fn next(&mut self) -> Option<ScalarCow<'s>> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.0.count()
    }
}

impl<'s> ExactSizeIterator for Keys<'s> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for Value {
    fn default() -> Self {
        Self::Nil
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Self) -> bool {
        crate::value_eq(self.as_view(), other.as_view())
    }
}

impl<'v> PartialEq<ValueViewCmp<'v>> for Value {
    fn eq(&self, other: &ValueViewCmp<'v>) -> bool {
        ValueViewCmp::new(self.as_view()) == *other
    }
}

impl<'v> PartialEq<ValueCow<'v>> for Value {
    fn eq(&self, other: &ValueCow<'v>) -> bool {
        crate::value_eq(self.as_view(), other.as_view())
    }
}

impl PartialEq<i32> for Value {
    fn eq(&self, other: &i32) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<f64> for Value {
    fn eq(&self, other: &f64) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<bool> for Value {
    fn eq(&self, other: &bool) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<crate::DateTime> for Value {
    fn eq(&self, other: &crate::DateTime) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<crate::Date> for Value {
    fn eq(&self, other: &crate::Date) -> bool {
        crate::value_eq(self, other)
    }
}

impl PartialEq<str> for Value {
    fn eq(&self, other: &str) -> bool {
        let other = KStringCow::from_ref(other);
        crate::value_eq(self, &other)
    }
}

impl<'s> PartialEq<&'s str> for Value {
    fn eq(&self, other: &&str) -> bool {
        crate::value_eq(self, other)
    }
}

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

impl PartialEq<kstring::KString> for Value {
    fn eq(&self, other: &kstring::KString) -> bool {
        crate::value_eq(self, &other.as_ref())
    }
}

impl<'s> PartialEq<kstring::KStringRef<'s>> for Value {
    fn eq(&self, other: &kstring::KStringRef<'s>) -> bool {
        crate::value_eq(self, other)
    }
}

impl<'s> PartialEq<kstring::KStringCow<'s>> for Value {
    fn eq(&self, other: &kstring::KStringCow<'s>) -> bool {
        crate::value_eq(self, other)
    }
}

impl Eq for Value {}

impl PartialOrd<Value> for Value {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        crate::value_cmp(self, other)
    }
}

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

    #[test]
    fn test_to_string_scalar() {
        let val = Value::scalar(42f64);
        assert_eq!(&val.render().to_string(), "42");
        assert_eq!(&val.to_kstr(), "42");
    }

    #[test]
    fn test_to_string_array() {
        let val = Value::Array(vec![
            Value::scalar(3f64),
            Value::scalar("test"),
            Value::scalar(5.3),
        ]);
        assert_eq!(&val.render().to_string(), "3test5.3");
        assert_eq!(&val.to_kstr(), "3test5.3");
    }

    // TODO make a test for object, remember values are in arbitrary orders in HashMaps

    #[test]
    fn test_to_string_nil() {
        assert_eq!(&Value::Nil.render().to_string(), "");
        assert_eq!(&Value::Nil.to_kstr(), "");
    }

    #[test]
    fn scalar_equality() {
        assert_eq!(Value::scalar("alpha"), Value::scalar("alpha"));
        assert_eq!(Value::scalar(""), Value::scalar(""));
        assert!(Value::scalar("alpha") != Value::scalar("beta"));
        assert!(Value::scalar("beta") != Value::scalar("alpha"));
    }

    #[test]
    fn scalars_have_ruby_truthiness() {
        // all strings in ruby are true
        assert_eq!(Value::scalar(true), Value::scalar("All strings are truthy"));
        assert_eq!(Value::scalar(true), Value::scalar(""));
        assert!(Value::scalar("").query_state(State::Truthy));

        assert_eq!(Value::scalar(true), Value::scalar(true));
        assert!(Value::scalar(true) != Value::scalar(false));
    }

    #[test]
    fn array_equality() {
        let a = Value::Array(vec![Value::scalar("one"), Value::scalar("two")]);
        let b = Value::Array(vec![Value::scalar("alpha"), Value::scalar("beta")]);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn arrays_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Array(Vec::new()));
        assert!(Value::Array(Vec::new()).query_state(State::Truthy));
    }

    #[test]
    fn object_equality() {
        let a: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
        ]
        .iter()
        .cloned()
        .collect();
        let a = Value::Object(a);

        let b: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
            ("gamma".into(), Value::Array(vec![])),
        ]
        .iter()
        .cloned()
        .collect();
        let b = Value::Object(b);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn objects_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Object(Object::new()));
        assert!(Value::Object(Object::new()).query_state(State::Truthy));
    }

    #[test]
    fn nil_equality() {
        assert_eq!(Value::Nil, Value::Nil);
    }

    #[test]
    fn nils_have_ruby_truthiness() {
        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(!Value::Nil.query_state(State::Truthy));

        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(Value::scalar(true) != Value::Nil);
        assert!(Value::scalar("") != Value::Nil);
    }

    #[test]
    fn empty_equality() {
        let blank = Value::State(State::Blank);
        let empty = Value::State(State::Empty);
        // Truth table from https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
        assert_eq!(empty, empty);
        assert_eq!(empty, blank);
        assert_eq!(empty, value!(""));
        assert_ne!(empty, value!(" "));
        assert_eq!(empty, value!([]));
        assert_ne!(empty, value!([nil]));
        assert_eq!(empty, value!({}));
        assert_ne!(empty, value!({ "a": nil }));
    }

    #[test]
    fn blank_equality() {
        let blank = Value::State(State::Blank);
        let empty = Value::State(State::Empty);
        // Truth table from https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
        assert_eq!(blank, blank);
        assert_eq!(blank, empty);
        assert_eq!(blank, value!(nil));
        assert_eq!(blank, value!(false));
        assert_ne!(blank, value!(true));
        assert_ne!(blank, value!(0));
        assert_ne!(blank, value!(1));
        assert_eq!(blank, value!(""));
        assert_eq!(blank, value!(" "));
        assert_eq!(blank, value!([]));
        assert_ne!(blank, value!([nil]));
        assert_eq!(blank, value!({}));
        assert_ne!(blank, value!({ "a": nil }));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Remotely authenticated vs. unauthenticated network end-points:
//! ---------------------------------------------------
//! A network end-point operates with remote authentication if it only accepts connections
//! from a known set of peers (`trusted_peers`) identified by their network identity keys.
//! This does not mean that the other end-point of a connection also needs to operate with
//! authentication -- a network end-point running with remote authentication enabled will
//! connect to or accept connections from an end-point running in authenticated mode as
//! long as the latter is in its trusted peers set.
use channel::{self, message_queues::QueueStyle};
use diem_config::{
    config::{
        DiscoveryMethod, NetworkConfig, Peer, PeerRole, PeerSet, RateLimitConfig, RoleType,
        CONNECTION_BACKOFF_BASE, CONNECTIVITY_CHECK_INTERVAL_MS, MAX_CONCURRENT_NETWORK_REQS,
        MAX_CONNECTION_DELAY_MS, MAX_FRAME_SIZE, MAX_FULLNODE_OUTBOUND_CONNECTIONS,
        MAX_INBOUND_CONNECTIONS, NETWORK_CHANNEL_SIZE,
    },
    network_id::NetworkContext,
};
use diem_crypto::x25519::PublicKey;
use diem_infallible::RwLock;
use diem_logger::prelude::*;
use diem_metrics::IntCounterVec;
use diem_network_address_encryption::Encryptor;
use diem_time_service::TimeService;
use diem_types::{chain_id::ChainId, network_address::NetworkAddress};
use network::{
    connectivity_manager::{builder::ConnectivityManagerBuilder, ConnectivityRequest},
    logging::NetworkSchema,
    peer_manager::{
        builder::{AuthenticationMode, PeerManagerBuilder},
        ConnectionRequestSender,
    },
    protocols::{
        health_checker::{self, builder::HealthCheckerBuilder},
        network::{NewNetworkEvents, NewNetworkSender},
    },
    ProtocolId,
};
use network_simple_onchain_discovery::{
    builder::ValidatorSetChangeListenerBuilder, gen_simple_discovery_reconfig_subscription,
};
use std::{clone::Clone, collections::HashMap, sync::Arc};
use subscription_service::ReconfigSubscription;
use tokio::runtime::Handle;

#[derive(Debug, PartialEq, PartialOrd)]
enum State {
    CREATED,
    BUILT,
    STARTED,
}

/// Build Network module with custom configuration values.
/// Methods can be chained in order to set the configuration values.
/// MempoolNetworkHandler and ConsensusNetworkHandler are constructed by calling
/// [`NetworkBuilder::build`].  New instances of `NetworkBuilder` are obtained
/// via [`NetworkBuilder::create`].
pub struct NetworkBuilder {
    state: State,
    executor: Option<Handle>,
    time_service: TimeService,
    network_context: Arc<NetworkContext>,

    validator_set_listener_builder: Option<ValidatorSetChangeListenerBuilder>,
    connectivity_manager_builder: Option<ConnectivityManagerBuilder>,
    health_checker_builder: Option<HealthCheckerBuilder>,
    peer_manager_builder: PeerManagerBuilder,

    // (StateSync) ReconfigSubscriptions required by internal Network components.
    reconfig_subscriptions: Vec<ReconfigSubscription>,
}

impl NetworkBuilder {
    /// Return a new NetworkBuilder initialized with default configuration values.
    // TODO:  Remove `pub`.  NetworkBuilder should only be created thorugh `::create()`
    pub fn new(
        chain_id: ChainId,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
        max_frame_size: usize,
        enable_proxy_protocol: bool,
        network_channel_size: usize,
        max_concurrent_network_reqs: usize,
        inbound_connection_limit: usize,
        inbound_rate_limit_config: Option<RateLimitConfig>,
        outbound_rate_limit_config: Option<RateLimitConfig>,
    ) -> Self {
        // A network cannot exist without a PeerManager
        // TODO:  construct this in create and pass it to new() as a parameter. The complication is manual construction of NetworkBuilder in various tests.
        let peer_manager_builder = PeerManagerBuilder::create(
            chain_id,
            network_context.clone(),
            time_service.clone(),
            listen_address,
            trusted_peers,
            authentication_mode,
            network_channel_size,
            max_concurrent_network_reqs,
            max_frame_size,
            enable_proxy_protocol,
            inbound_connection_limit,
            inbound_rate_limit_config,
            outbound_rate_limit_config,
        );

        NetworkBuilder {
            state: State::CREATED,
            executor: None,
            time_service,
            network_context,
            validator_set_listener_builder: None,
            connectivity_manager_builder: None,
            health_checker_builder: None,
            peer_manager_builder,
            reconfig_subscriptions: vec![],
        }
    }

    pub fn new_for_test(
        chain_id: ChainId,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
    ) -> NetworkBuilder {
        let mutual_authentication = matches!(authentication_mode, AuthenticationMode::Mutual(_));

        let mut builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            listen_address,
            authentication_mode,
            MAX_FRAME_SIZE,
            false, /* Disable proxy protocol */
            NETWORK_CHANNEL_SIZE,
            MAX_CONCURRENT_NETWORK_REQS,
            MAX_INBOUND_CONNECTIONS,
            None,
            None,
        );

        builder.add_connectivity_manager(
            seeds,
            trusted_peers,
            MAX_FULLNODE_OUTBOUND_CONNECTIONS,
            CONNECTION_BACKOFF_BASE,
            MAX_CONNECTION_DELAY_MS,
            CONNECTIVITY_CHECK_INTERVAL_MS,
            NETWORK_CHANNEL_SIZE,
            mutual_authentication,
        );

        builder
    }

    /// Create a new NetworkBuilder based on the provided configuration.
    pub fn create(
        chain_id: ChainId,
        role: RoleType,
        config: &NetworkConfig,
        time_service: TimeService,
    ) -> NetworkBuilder {
        let peer_id = config.peer_id();
        let identity_key = config.identity_key();
        let pubkey = identity_key.public_key();

        let authentication_mode = if config.mutual_authentication {
            AuthenticationMode::Mutual(identity_key)
        } else {
            AuthenticationMode::MaybeMutual(identity_key)
        };

        let network_context = Arc::new(NetworkContext::new(
            role,
            config.network_id.clone(),
            peer_id,
        ));

        let trusted_peers = Arc::new(RwLock::new(HashMap::new()));

        let mut network_builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            config.listen_address.clone(),
            authentication_mode,
            config.max_frame_size,
            config.enable_proxy_protocol,
            config.network_channel_size,
            config.max_concurrent_network_reqs,
            config.max_inbound_connections,
            config.inbound_rate_limit_config,
            config.outbound_rate_limit_config,
        );

        network_builder.add_connection_monitoring(
            config.ping_interval_ms,
            config.ping_timeout_ms,
            config.ping_failures_tolerated,
        );

        // Don't turn on connectivity manager if we're a public-facing server,
        // for example.
        //
        // Cases that require connectivity manager:
        //
        // 1) mutual authentication networks currently require connmgr to set the
        //    trusted peers set.
        // 2) networks with a discovery protocol need connmgr to connect to newly
        //    discovered peers.
        // 3) if we have seed peers, then we need connmgr to connect to them.
        // TODO(philiphayes): could probably use a better way to specify these cases
        // TODO:  Why not add ConnectivityManager always?
        if config.mutual_authentication
            || config.discovery_method != DiscoveryMethod::None
            || !config.seed_addrs.is_empty()
            || !config.seeds.is_empty()
        {
            let seeds = merge_seeds(config);

            network_builder.add_connectivity_manager(
                seeds,
                trusted_peers,
                config.max_outbound_connections,
                config.connection_backoff_base,
                config.max_connection_delay_ms,
                config.connectivity_check_interval_ms,
                config.network_channel_size,
                config.mutual_authentication,
            );
        }

        match &config.discovery_method {
            DiscoveryMethod::Onchain => {
                network_builder.add_validator_set_listener(pubkey, config.encryptor());
            }
            DiscoveryMethod::None => {}
        }

        network_builder
    }

    /// Create the configured Networking components.
    pub fn build(&mut self, executor: Handle) -> &mut Self {
        assert_eq!(self.state, State::CREATED);
        self.state = State::BUILT;
        self.executor = Some(executor);
        self.peer_manager_builder
            .build(self.executor.as_mut().expect("Executor must exist"));
        self
    }

    /// Start the built Networking components.
    pub fn start(&mut self) -> &mut Self {
        assert_eq!(self.state, State::BUILT);
        self.state = State::STARTED;

        let executor = self.executor.as_mut().expect("Executor must exist");
        self.peer_manager_builder.start(executor);
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Started peer manager", self.network_context
        );

        if let Some(conn_mgr_builder) = self.connectivity_manager_builder.as_mut() {
            conn_mgr_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started conn manager", self.network_context
            );
        }

        if let Some(health_checker_builder) = self.health_checker_builder.as_mut() {
            health_checker_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started health checker", self.network_context
            );
        }

        if let Some(validator_set_listener_builder) = self.validator_set_listener_builder.as_mut() {
            validator_set_listener_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started validator set listener", self.network_context
            );
        }
        self
    }

    pub fn reconfig_subscriptions(&mut self) -> &mut Vec<ReconfigSubscription> {
        &mut self.reconfig_subscriptions
    }

    pub fn network_context(&self) -> Arc<NetworkContext> {
        self.network_context.clone()
    }

    pub fn conn_mgr_reqs_tx(&self) -> Option<channel::Sender<ConnectivityRequest>> {
        self.connectivity_manager_builder
            .as_ref()
            .map(|conn_mgr_builder| conn_mgr_builder.conn_mgr_reqs_tx())
    }

    pub fn listen_address(&self) -> NetworkAddress {
        self.peer_manager_builder.listen_address()
    }

    /// Add a [`ConnectivityManager`] to the network.
    ///
    /// [`ConnectivityManager`] is responsible for ensuring that we are connected
    /// to a node iff. it is an eligible node and maintaining persistent
    /// connections with all eligible nodes. A list of eligible nodes is received
    /// at initialization, and updates are received on changes to system membership.
    ///
    /// Note: a connectivity manager should only be added if the network is
    /// permissioned.
    pub fn add_connectivity_manager(
        &mut self,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        max_outbound_connections: usize,
        connection_backoff_base: u64,
        max_connection_delay_ms: u64,
        connectivity_check_interval_ms: u64,
        channel_size: usize,
        mutual_authentication: bool,
    ) -> &mut Self {
        let pm_conn_mgr_notifs_rx = self.peer_manager_builder.add_connection_event_listener();
        let outbound_connection_limit = if !self.network_context.network_id().is_validator_network()
        {
            Some(max_outbound_connections)
        } else {
            None
        };

        self.connectivity_manager_builder = Some(ConnectivityManagerBuilder::create(
            self.network_context(),
            self.time_service.clone(),
            trusted_peers,
            seeds,
            connectivity_check_interval_ms,
            connection_backoff_base,
            max_connection_delay_ms,
            channel_size,
            ConnectionRequestSender::new(self.peer_manager_builder.connection_reqs_tx()),
            pm_conn_mgr_notifs_rx,
            outbound_connection_limit,
            mutual_authentication,
        ));
        self
    }

    fn add_validator_set_listener(&mut self, pubkey: PublicKey, encryptor: Encryptor) -> &mut Self {
        let conn_mgr_reqs_tx = self
            .conn_mgr_reqs_tx()
            .expect("ConnectivityManager must be installed for validator");
        let (simple_discovery_reconfig_subscription, simple_discovery_reconfig_rx) =
            gen_simple_discovery_reconfig_subscription();
        self.reconfig_subscriptions
            .push(simple_discovery_reconfig_subscription);

        self.validator_set_listener_builder = Some(ValidatorSetChangeListenerBuilder::create(
            self.network_context.clone(),
            pubkey,
            encryptor,
            conn_mgr_reqs_tx,
            simple_discovery_reconfig_rx,
        ));
        self
    }

    /// Add a HealthChecker to the network.
    fn add_connection_monitoring(
        &mut self,
        ping_interval_ms: u64,
        ping_timeout_ms: u64,
        ping_failures_tolerated: u64,
    ) -> &mut Self {
        // Initialize and start HealthChecker.
        let (hc_network_tx, hc_network_rx) =
            self.add_protocol_handler(health_checker::network_endpoint_config());

        self.health_checker_builder = Some(HealthCheckerBuilder::new(
            self.network_context(),
            self.time_service.clone(),
            ping_interval_ms,
            ping_timeout_ms,
            ping_failures_tolerated,
            hc_network_tx,
            hc_network_rx,
        ));
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Created health checker", self.network_context
        );
        self
    }

    /// Adds a endpoints for the provided configuration.  Returns NetworkSender and NetworkEvent which
    /// can be attached to other components.
    pub fn add_protocol_handler<SenderT, EventT>(
        &mut self,
        (rpc_protocols, direct_send_protocols, queue_preference, max_queue_size_per_peer, counter): (
            Vec<ProtocolId>,
            Vec<ProtocolId>,
            QueueStyle,
            usize,
            Option<&'static IntCounterVec>,
        ),
    ) -> (SenderT, EventT)
    where
        EventT: NewNetworkEvents,
        SenderT: NewNetworkSender,
    {
        let (peer_mgr_reqs_tx, peer_mgr_reqs_rx, connection_reqs_tx, connection_notifs_rx) =
            self.peer_manager_builder.add_protocol_handler(
                rpc_protocols,
                direct_send_protocols,
                queue_preference,
                max_queue_size_per_peer,
                counter,
            );
        (
            SenderT::new(peer_mgr_reqs_tx, connection_reqs_tx),
            EventT::new(peer_mgr_reqs_rx, connection_notifs_rx),
        )
    }
}

/// Retrieve and merge seeds so that they have all keys associated
fn merge_seeds(config: &NetworkConfig) -> PeerSet {
    config.verify_seeds().expect("Seeds must be well formed");
    let mut seeds = config.seeds.clone();

    // Merge old seed configuration with new seed configuration
    // TODO(gnazario): Once fully migrated, remove `seed_addrs`
    config
        .seed_addrs
        .iter()
        .map(|(peer_id, addrs)| {
            (
                peer_id,
                Peer::from_addrs(PeerRole::ValidatorFullNode, addrs.clone()),
            )
        })
        .for_each(|(peer_id, peer)| {
            seeds
                .entry(*peer_id)
                // Sad clone due to Rust not realizing these are two distinct paths
                .and_modify(|seed| seed.extend(peer.clone()).unwrap())
                .or_insert(peer);
        });

    // Pull public keys out of addresses
    seeds.values_mut().for_each(
        |Peer {
             addresses, keys, ..
         }| {
            addresses
                .iter()
                .filter_map(NetworkAddress::find_noise_proto)
                .for_each(|pubkey| {
                    keys.insert(pubkey);
                });
        },
    );
    seeds
}
<commit_msg>[network] Always enable connectivity manager<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Remotely authenticated vs. unauthenticated network end-points:
//! ---------------------------------------------------
//! A network end-point operates with remote authentication if it only accepts connections
//! from a known set of peers (`trusted_peers`) identified by their network identity keys.
//! This does not mean that the other end-point of a connection also needs to operate with
//! authentication -- a network end-point running with remote authentication enabled will
//! connect to or accept connections from an end-point running in authenticated mode as
//! long as the latter is in its trusted peers set.
use channel::{self, message_queues::QueueStyle};
use diem_config::{
    config::{
        DiscoveryMethod, NetworkConfig, Peer, PeerRole, PeerSet, RateLimitConfig, RoleType,
        CONNECTION_BACKOFF_BASE, CONNECTIVITY_CHECK_INTERVAL_MS, MAX_CONCURRENT_NETWORK_REQS,
        MAX_CONNECTION_DELAY_MS, MAX_FRAME_SIZE, MAX_FULLNODE_OUTBOUND_CONNECTIONS,
        MAX_INBOUND_CONNECTIONS, NETWORK_CHANNEL_SIZE,
    },
    network_id::NetworkContext,
};
use diem_crypto::x25519::PublicKey;
use diem_infallible::RwLock;
use diem_logger::prelude::*;
use diem_metrics::IntCounterVec;
use diem_network_address_encryption::Encryptor;
use diem_time_service::TimeService;
use diem_types::{chain_id::ChainId, network_address::NetworkAddress};
use network::{
    connectivity_manager::{builder::ConnectivityManagerBuilder, ConnectivityRequest},
    logging::NetworkSchema,
    peer_manager::{
        builder::{AuthenticationMode, PeerManagerBuilder},
        ConnectionRequestSender,
    },
    protocols::{
        health_checker::{self, builder::HealthCheckerBuilder},
        network::{NewNetworkEvents, NewNetworkSender},
    },
    ProtocolId,
};
use network_simple_onchain_discovery::{
    builder::ValidatorSetChangeListenerBuilder, gen_simple_discovery_reconfig_subscription,
};
use std::{clone::Clone, collections::HashMap, sync::Arc};
use subscription_service::ReconfigSubscription;
use tokio::runtime::Handle;

#[derive(Debug, PartialEq, PartialOrd)]
enum State {
    CREATED,
    BUILT,
    STARTED,
}

/// Build Network module with custom configuration values.
/// Methods can be chained in order to set the configuration values.
/// MempoolNetworkHandler and ConsensusNetworkHandler are constructed by calling
/// [`NetworkBuilder::build`].  New instances of `NetworkBuilder` are obtained
/// via [`NetworkBuilder::create`].
pub struct NetworkBuilder {
    state: State,
    executor: Option<Handle>,
    time_service: TimeService,
    network_context: Arc<NetworkContext>,

    validator_set_listener_builder: Option<ValidatorSetChangeListenerBuilder>,
    connectivity_manager_builder: Option<ConnectivityManagerBuilder>,
    health_checker_builder: Option<HealthCheckerBuilder>,
    peer_manager_builder: PeerManagerBuilder,

    // (StateSync) ReconfigSubscriptions required by internal Network components.
    reconfig_subscriptions: Vec<ReconfigSubscription>,
}

impl NetworkBuilder {
    /// Return a new NetworkBuilder initialized with default configuration values.
    // TODO:  Remove `pub`.  NetworkBuilder should only be created thorugh `::create()`
    pub fn new(
        chain_id: ChainId,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
        max_frame_size: usize,
        enable_proxy_protocol: bool,
        network_channel_size: usize,
        max_concurrent_network_reqs: usize,
        inbound_connection_limit: usize,
        inbound_rate_limit_config: Option<RateLimitConfig>,
        outbound_rate_limit_config: Option<RateLimitConfig>,
    ) -> Self {
        // A network cannot exist without a PeerManager
        // TODO:  construct this in create and pass it to new() as a parameter. The complication is manual construction of NetworkBuilder in various tests.
        let peer_manager_builder = PeerManagerBuilder::create(
            chain_id,
            network_context.clone(),
            time_service.clone(),
            listen_address,
            trusted_peers,
            authentication_mode,
            network_channel_size,
            max_concurrent_network_reqs,
            max_frame_size,
            enable_proxy_protocol,
            inbound_connection_limit,
            inbound_rate_limit_config,
            outbound_rate_limit_config,
        );

        NetworkBuilder {
            state: State::CREATED,
            executor: None,
            time_service,
            network_context,
            validator_set_listener_builder: None,
            connectivity_manager_builder: None,
            health_checker_builder: None,
            peer_manager_builder,
            reconfig_subscriptions: vec![],
        }
    }

    pub fn new_for_test(
        chain_id: ChainId,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
    ) -> NetworkBuilder {
        let mutual_authentication = matches!(authentication_mode, AuthenticationMode::Mutual(_));

        let mut builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            listen_address,
            authentication_mode,
            MAX_FRAME_SIZE,
            false, /* Disable proxy protocol */
            NETWORK_CHANNEL_SIZE,
            MAX_CONCURRENT_NETWORK_REQS,
            MAX_INBOUND_CONNECTIONS,
            None,
            None,
        );

        builder.add_connectivity_manager(
            seeds,
            trusted_peers,
            MAX_FULLNODE_OUTBOUND_CONNECTIONS,
            CONNECTION_BACKOFF_BASE,
            MAX_CONNECTION_DELAY_MS,
            CONNECTIVITY_CHECK_INTERVAL_MS,
            NETWORK_CHANNEL_SIZE,
            mutual_authentication,
        );

        builder
    }

    /// Create a new NetworkBuilder based on the provided configuration.
    pub fn create(
        chain_id: ChainId,
        role: RoleType,
        config: &NetworkConfig,
        time_service: TimeService,
    ) -> NetworkBuilder {
        let peer_id = config.peer_id();
        let identity_key = config.identity_key();
        let pubkey = identity_key.public_key();

        let authentication_mode = if config.mutual_authentication {
            AuthenticationMode::Mutual(identity_key)
        } else {
            AuthenticationMode::MaybeMutual(identity_key)
        };

        let network_context = Arc::new(NetworkContext::new(
            role,
            config.network_id.clone(),
            peer_id,
        ));

        let trusted_peers = Arc::new(RwLock::new(HashMap::new()));

        let mut network_builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            config.listen_address.clone(),
            authentication_mode,
            config.max_frame_size,
            config.enable_proxy_protocol,
            config.network_channel_size,
            config.max_concurrent_network_reqs,
            config.max_inbound_connections,
            config.inbound_rate_limit_config,
            config.outbound_rate_limit_config,
        );

        network_builder.add_connection_monitoring(
            config.ping_interval_ms,
            config.ping_timeout_ms,
            config.ping_failures_tolerated,
        );

        // Always add a connectivity manager to keep track of known peers
        let seeds = merge_seeds(config);

        network_builder.add_connectivity_manager(
            seeds,
            trusted_peers,
            config.max_outbound_connections,
            config.connection_backoff_base,
            config.max_connection_delay_ms,
            config.connectivity_check_interval_ms,
            config.network_channel_size,
            config.mutual_authentication,
        );

        match &config.discovery_method {
            DiscoveryMethod::Onchain => {
                network_builder.add_validator_set_listener(pubkey, config.encryptor());
            }
            DiscoveryMethod::None => {}
        }

        network_builder
    }

    /// Create the configured Networking components.
    pub fn build(&mut self, executor: Handle) -> &mut Self {
        assert_eq!(self.state, State::CREATED);
        self.state = State::BUILT;
        self.executor = Some(executor);
        self.peer_manager_builder
            .build(self.executor.as_mut().expect("Executor must exist"));
        self
    }

    /// Start the built Networking components.
    pub fn start(&mut self) -> &mut Self {
        assert_eq!(self.state, State::BUILT);
        self.state = State::STARTED;

        let executor = self.executor.as_mut().expect("Executor must exist");
        self.peer_manager_builder.start(executor);
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Started peer manager", self.network_context
        );

        if let Some(conn_mgr_builder) = self.connectivity_manager_builder.as_mut() {
            conn_mgr_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started conn manager", self.network_context
            );
        }

        if let Some(health_checker_builder) = self.health_checker_builder.as_mut() {
            health_checker_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started health checker", self.network_context
            );
        }

        if let Some(validator_set_listener_builder) = self.validator_set_listener_builder.as_mut() {
            validator_set_listener_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started validator set listener", self.network_context
            );
        }
        self
    }

    pub fn reconfig_subscriptions(&mut self) -> &mut Vec<ReconfigSubscription> {
        &mut self.reconfig_subscriptions
    }

    pub fn network_context(&self) -> Arc<NetworkContext> {
        self.network_context.clone()
    }

    pub fn conn_mgr_reqs_tx(&self) -> Option<channel::Sender<ConnectivityRequest>> {
        self.connectivity_manager_builder
            .as_ref()
            .map(|conn_mgr_builder| conn_mgr_builder.conn_mgr_reqs_tx())
    }

    pub fn listen_address(&self) -> NetworkAddress {
        self.peer_manager_builder.listen_address()
    }

    /// Add a [`ConnectivityManager`] to the network.
    ///
    /// [`ConnectivityManager`] is responsible for ensuring that we are connected
    /// to a node iff. it is an eligible node and maintaining persistent
    /// connections with all eligible nodes. A list of eligible nodes is received
    /// at initialization, and updates are received on changes to system membership.
    ///
    /// Note: a connectivity manager should only be added if the network is
    /// permissioned.
    pub fn add_connectivity_manager(
        &mut self,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        max_outbound_connections: usize,
        connection_backoff_base: u64,
        max_connection_delay_ms: u64,
        connectivity_check_interval_ms: u64,
        channel_size: usize,
        mutual_authentication: bool,
    ) -> &mut Self {
        let pm_conn_mgr_notifs_rx = self.peer_manager_builder.add_connection_event_listener();
        let outbound_connection_limit = if !self.network_context.network_id().is_validator_network()
        {
            Some(max_outbound_connections)
        } else {
            None
        };

        self.connectivity_manager_builder = Some(ConnectivityManagerBuilder::create(
            self.network_context(),
            self.time_service.clone(),
            trusted_peers,
            seeds,
            connectivity_check_interval_ms,
            connection_backoff_base,
            max_connection_delay_ms,
            channel_size,
            ConnectionRequestSender::new(self.peer_manager_builder.connection_reqs_tx()),
            pm_conn_mgr_notifs_rx,
            outbound_connection_limit,
            mutual_authentication,
        ));
        self
    }

    fn add_validator_set_listener(&mut self, pubkey: PublicKey, encryptor: Encryptor) -> &mut Self {
        let conn_mgr_reqs_tx = self
            .conn_mgr_reqs_tx()
            .expect("ConnectivityManager must be installed for validator");
        let (simple_discovery_reconfig_subscription, simple_discovery_reconfig_rx) =
            gen_simple_discovery_reconfig_subscription();
        self.reconfig_subscriptions
            .push(simple_discovery_reconfig_subscription);

        self.validator_set_listener_builder = Some(ValidatorSetChangeListenerBuilder::create(
            self.network_context.clone(),
            pubkey,
            encryptor,
            conn_mgr_reqs_tx,
            simple_discovery_reconfig_rx,
        ));
        self
    }

    /// Add a HealthChecker to the network.
    fn add_connection_monitoring(
        &mut self,
        ping_interval_ms: u64,
        ping_timeout_ms: u64,
        ping_failures_tolerated: u64,
    ) -> &mut Self {
        // Initialize and start HealthChecker.
        let (hc_network_tx, hc_network_rx) =
            self.add_protocol_handler(health_checker::network_endpoint_config());

        self.health_checker_builder = Some(HealthCheckerBuilder::new(
            self.network_context(),
            self.time_service.clone(),
            ping_interval_ms,
            ping_timeout_ms,
            ping_failures_tolerated,
            hc_network_tx,
            hc_network_rx,
        ));
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Created health checker", self.network_context
        );
        self
    }

    /// Adds a endpoints for the provided configuration.  Returns NetworkSender and NetworkEvent which
    /// can be attached to other components.
    pub fn add_protocol_handler<SenderT, EventT>(
        &mut self,
        (rpc_protocols, direct_send_protocols, queue_preference, max_queue_size_per_peer, counter): (
            Vec<ProtocolId>,
            Vec<ProtocolId>,
            QueueStyle,
            usize,
            Option<&'static IntCounterVec>,
        ),
    ) -> (SenderT, EventT)
    where
        EventT: NewNetworkEvents,
        SenderT: NewNetworkSender,
    {
        let (peer_mgr_reqs_tx, peer_mgr_reqs_rx, connection_reqs_tx, connection_notifs_rx) =
            self.peer_manager_builder.add_protocol_handler(
                rpc_protocols,
                direct_send_protocols,
                queue_preference,
                max_queue_size_per_peer,
                counter,
            );
        (
            SenderT::new(peer_mgr_reqs_tx, connection_reqs_tx),
            EventT::new(peer_mgr_reqs_rx, connection_notifs_rx),
        )
    }
}

/// Retrieve and merge seeds so that they have all keys associated
fn merge_seeds(config: &NetworkConfig) -> PeerSet {
    config.verify_seeds().expect("Seeds must be well formed");
    let mut seeds = config.seeds.clone();

    // Merge old seed configuration with new seed configuration
    // TODO(gnazario): Once fully migrated, remove `seed_addrs`
    config
        .seed_addrs
        .iter()
        .map(|(peer_id, addrs)| {
            (
                peer_id,
                Peer::from_addrs(PeerRole::ValidatorFullNode, addrs.clone()),
            )
        })
        .for_each(|(peer_id, peer)| {
            seeds
                .entry(*peer_id)
                // Sad clone due to Rust not realizing these are two distinct paths
                .and_modify(|seed| seed.extend(peer.clone()).unwrap())
                .or_insert(peer);
        });

    // Pull public keys out of addresses
    seeds.values_mut().for_each(
        |Peer {
             addresses, keys, ..
         }| {
            addresses
                .iter()
                .filter_map(NetworkAddress::find_noise_proto)
                .for_each(|pubkey| {
                    keys.insert(pubkey);
                });
        },
    );
    seeds
}
<|endoftext|>


<commit_before>use std::fmt;
use hyper;
use hyper::Client;
use hyper::client::Response as HyperResponse;
use hyper::header::{Headers, Accept, Authorization, Connection, UserAgent, qitem};
use regex::Regex;
use rustc_serialize::json;
use std::io::Read;
use std::process;

use say;
use github;

header! { (XRateLimitRemaining, "X-RateLimit-Remaining") => [u32] }

header! { (Link, "Link") => [String] }

/// The result of processing a response.
/// TODO: Unify with Page
#[derive(Debug)]
pub struct Response {
    pub content: String,
    pub ratelimit: u32,
}

impl From<HyperResponse> for Response {
    fn from(mut res: HyperResponse) -> Self {
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        Response { content: body
                 , ratelimit: ratelimit(&res.headers)
                 }
    }
}

/// The result of processing a response.
pub struct Page {
    pub content: String,
    pub next: Option<String>,
    pub ratelimit: u32,
}

impl Page {
    pub fn new(url: &str, token: &str) -> Page {
        let mut res = get_page(url.to_string(), token);
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        Page {content: body,
              next: next_url(link(&res.headers)),
              ratelimit: ratelimit(&res.headers)}
    }

    pub fn warn(&self) {
        if self.next.is_none() {
            println!("{} {} {}", say::warn(), self.ratelimit, "Remaining requests");
        }
    }
}

impl fmt::Display for Page {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{{next: {:?}, ratelimit: {}}}", self.next, self.ratelimit)
    }
}

fn get_page(url: String, token: &str) -> HyperResponse {
    println!("{} {} {}", say::info(), "Fetching", url);

    let client = Client::new();
    let res = client.get(&*url.clone())
                    .header(UserAgent(format!("nerve/{}", env!("CARGO_PKG_VERSION"))))
                    .header(Authorization(format!("token {}", token)))
                    .header(Accept(vec![qitem(github::mime())]))
                    .header(Connection::close())
                    .send().unwrap_or_else(|_| process::exit(1));

    match res.status {
        hyper::Ok => {}
        _ => {
            println!("{} {}", say::error(), "Unable to parse the response from Github");
            process::exit(1)
        }
    }

    res
}

pub fn ratelimit(headers: &Headers) -> u32 {
    match headers.get() {
        Some(&XRateLimitRemaining(x)) => x,
        None => 0
    }
}

pub fn warn_ratelimit(ratelimit: u32) {
    println!("{} {} {}", say::warn(), ratelimit, "Remaining requests");
}

// A Link header is not present if the requested collection has less than
// _pagesize_.
pub fn link(headers: &Headers) -> String {
    match headers.get() {
        Some(&Link(ref x)) => x.to_string(),
        None => "".to_string()
    }
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

/// A response error.
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct ResponseError {
    pub message: String,
    pub errors: Vec<ErrorResource>,
}

impl ResponseError {
    pub fn from_str(data: &str) -> Result<ResponseError, json::DecoderError> {
        json::decode(data)
    }
}

impl fmt::Display for ResponseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let error = self.errors.first().unwrap();

        write!(f, "the field '{}' {}", error.field, "has an invalid value.")
    }
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct ErrorResource {
    pub code: String,
    pub resource: String,
    pub field: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub enum ErrorName {
    Invalid,
    Missing,
    MissingField,
    AlreadyExists,
}
<commit_msg>feat(response): Add ErrorCode<commit_after>use std::fmt;
use hyper;
use hyper::Client;
use hyper::client::Response as HyperResponse;
use hyper::header::{Headers, Accept, Authorization, Connection, UserAgent, qitem};
use regex::Regex;
use rustc_serialize::json;
use std::io::Read;
use std::process;

use say;
use github;

header! { (XRateLimitRemaining, "X-RateLimit-Remaining") => [u32] }

header! { (Link, "Link") => [String] }

/// The result of processing a response.
/// TODO: Unify with Page
#[derive(Debug)]
pub struct Response {
    pub content: String,
    pub ratelimit: u32,
}

impl From<HyperResponse> for Response {
    fn from(mut res: HyperResponse) -> Self {
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        Response { content: body
                 , ratelimit: ratelimit(&res.headers)
                 }
    }
}

/// The result of processing a response.
pub struct Page {
    pub content: String,
    pub next: Option<String>,
    pub ratelimit: u32,
}

impl Page {
    pub fn new(url: &str, token: &str) -> Page {
        let mut res = get_page(url.to_string(), token);
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        Page {content: body,
              next: next_url(link(&res.headers)),
              ratelimit: ratelimit(&res.headers)}
    }

    pub fn warn(&self) {
        if self.next.is_none() {
            println!("{} {} {}", say::warn(), self.ratelimit, "Remaining requests");
        }
    }
}

impl fmt::Display for Page {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{{next: {:?}, ratelimit: {}}}", self.next, self.ratelimit)
    }
}

fn get_page(url: String, token: &str) -> HyperResponse {
    println!("{} {} {}", say::info(), "Fetching", url);

    let client = Client::new();
    let res = client.get(&*url.clone())
                    .header(UserAgent(format!("nerve/{}", env!("CARGO_PKG_VERSION"))))
                    .header(Authorization(format!("token {}", token)))
                    .header(Accept(vec![qitem(github::mime())]))
                    .header(Connection::close())
                    .send().unwrap_or_else(|_| process::exit(1));

    match res.status {
        hyper::Ok => {}
        _ => {
            println!("{} {}", say::error(), "Unable to parse the response from Github");
            process::exit(1)
        }
    }

    res
}

pub fn ratelimit(headers: &Headers) -> u32 {
    match headers.get() {
        Some(&XRateLimitRemaining(x)) => x,
        None => 0
    }
}

pub fn warn_ratelimit(ratelimit: u32) {
    println!("{} {} {}", say::warn(), ratelimit, "Remaining requests");
}

// A Link header is not present if the requested collection has less than
// _pagesize_.
pub fn link(headers: &Headers) -> String {
    match headers.get() {
        Some(&Link(ref x)) => x.to_string(),
        None => "".to_string()
    }
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

/// A response error.
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct ResponseError {
    pub message: String,
    pub errors: Vec<ErrorResource>,
}

impl ResponseError {
    pub fn from_str(data: &str) -> Result<ResponseError, json::DecoderError> {
        json::decode(data)
    }
}

impl fmt::Display for ResponseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: Check situations with multiple errors.
        let error = self.errors.first().unwrap();

        write!(f, "the field '{}' {}", error.field, "has an invalid value.")
    }
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct ErrorResource {
    pub code: ErrorCode,
    pub resource: String,
    pub field: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub enum ErrorCode {
    Invalid,
    Missing,
    MissingField,
    AlreadyExists,
}
<|endoftext|>


<commit_before>// Tuples can be used as function arguments and as return values
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // `let` can be used to bind the members of a tuple to variables
    let (integer, boolean) = pair;

    (boolean, integer)
}

fn main() {
    // A tuple with a bunch of different types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Values can be extracted from the tuple using the `.N` syntax
    println!("long tuple first value: {}", long_tuple.0);
    println!("long tuple second value: {}", long_tuple.1);

    // Tuples can be tuple members
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // Tuples are printable
    println!("tuple of tuples: {:?}", tuple_of_tuples);

    let pair = (1, true);
    println!("pair is {:?}", pair);

    println!("the reversed pair is {:?}", reverse(pair));

    // To create one element tuples, the comma is required to tell them apart
    // from a literal surrounded by parentheses
    println!("one element tuple: {:?}", (5u32,));
    println!("just an integer: {:?}", (5u32));
}
<commit_msg>rephrase tuple indexing<commit_after>// Tuples can be used as function arguments and as return values
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // `let` can be used to bind the members of a tuple to variables
    let (integer, boolean) = pair;

    (boolean, integer)
}

fn main() {
    // A tuple with a bunch of different types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Values can be extracted from the tuple using tuple indexing
    println!("long tuple first value: {}", long_tuple.0);
    println!("long tuple second value: {}", long_tuple.1);

    // Tuples can be tuple members
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // Tuples are printable
    println!("tuple of tuples: {:?}", tuple_of_tuples);

    let pair = (1, true);
    println!("pair is {:?}", pair);

    println!("the reversed pair is {:?}", reverse(pair));

    // To create one element tuples, the comma is required to tell them apart
    // from a literal surrounded by parentheses
    println!("one element tuple: {:?}", (5u32,));
    println!("just an integer: {:?}", (5u32));
}
<|endoftext|>


<commit_before><commit_msg>Better diagnostic<commit_after><|endoftext|>


<commit_before>extern crate iron;
extern crate handlebars_iron as hbs;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::{status};
use hbs::{Template, HandlebarsEngine, Watchable};
use rustc_serialize::json::{ToJson, Json};
use std::collections::BTreeMap;
use std::sync::Arc;

struct Team {
    name: String,
    pts: u16
}

impl ToJson for Team {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("name".to_string(), self.name.to_json());
        m.insert("pts".to_string(), self.pts.to_json());
        m.to_json()
    }
}

fn make_data () -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let teams = vec![ Team { name: "Jiangsu Sainty".to_string(),
                             pts: 43u16 },
                      Team { name: "Beijing Guoan".to_string(),
                             pts: 27u16 },
                      Team { name: "Guangzhou Evergrand".to_string(),
                             pts: 22u16 },
                      Team { name: "Shandong Luneng".to_string(),
                             pts: 12u16 } ];

    data.insert("teams".to_string(), teams.to_json());
    data
}

/// the handler
fn hello_world(_: &mut Request) -> IronResult<Response> {
    let mut resp = Response::new();

    let data = make_data();
    resp.set_mut(Template::new("index", data)).set_mut(status::Ok);
    Ok(resp)
}

fn main() {
    let mut chain = Chain::new(hello_world);
    let template_engine_ref = Arc::new(HandlebarsEngine::new("./examples/templates/", ".hbs"));
    template_engine_ref.watch();

    chain.link_after(template_engine_ref);

    println!("Server running at http://localhost:3000/");
    Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>(fix) fixed example only for watch feature<commit_after>#![allow(dead_code, unused_imports)]
extern crate iron;
extern crate handlebars_iron as hbs;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::{status};
use hbs::{Template, HandlebarsEngine};
#[cfg(feature = "watch")]
use hbs::Watchable;
use rustc_serialize::json::{ToJson, Json};
use std::collections::BTreeMap;
use std::sync::Arc;

struct Team {
    name: String,
    pts: u16
}

impl ToJson for Team {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("name".to_string(), self.name.to_json());
        m.insert("pts".to_string(), self.pts.to_json());
        m.to_json()
    }
}

fn make_data () -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let teams = vec![ Team { name: "Jiangsu Sainty".to_string(),
                             pts: 43u16 },
                      Team { name: "Beijing Guoan".to_string(),
                             pts: 27u16 },
                      Team { name: "Guangzhou Evergrand".to_string(),
                             pts: 22u16 },
                      Team { name: "Shandong Luneng".to_string(),
                             pts: 12u16 } ];

    data.insert("teams".to_string(), teams.to_json());
    data
}

/// the handler
fn hello_world(_: &mut Request) -> IronResult<Response> {
    let mut resp = Response::new();

    let data = make_data();
    resp.set_mut(Template::new("index", data)).set_mut(status::Ok);
    Ok(resp)
}

#[cfg(feature = "watch")]
fn main() {
    let mut chain = Chain::new(hello_world);
    let template_engine_ref = Arc::new(HandlebarsEngine::new("./examples/templates/", ".hbs"));
    template_engine_ref.watch();

    chain.link_after(template_engine_ref);

    println!("Server running at http://localhost:3000/");
    Iron::new(chain).http("localhost:3000").unwrap();
}

#[cfg(not(feature = "watch"))]
fn main() {
    println!("Watch only enabled via --features watch option");
}
<|endoftext|>