<commit_before>//! Custom input types
//!

use traits::{AsBytes, AtEof, Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, Offset, ParseTo, Slice};

use std::str::{self, CharIndices, Chars, FromStr};
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use std::iter::{Enumerate, Map};
use std::slice::Iter;

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct CompleteStr<'a>(pub &'a str);

impl<'a> AtEof for CompleteStr<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteStr<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteStr<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteStr<'a> {
  type Item = char;
  type RawItem = char;
  type Iter = CharIndices<'a>;
  type IterElem = Chars<'a>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteStr<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteStr(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteStr(left), CompleteStr(right))
  }
}

impl<'a> InputLength for CompleteStr<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteStr<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteStr<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteStr<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteStr<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteStr<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteStr<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse().ok()
  }
}

impl<'a> Offset for CompleteStr<'a> {
  fn offset(&self, second: &CompleteStr<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteStr<'a> {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(self.0)
  }
}

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct CompleteByteSlice<'a>(pub &'a [u8]);

impl<'a> AtEof for CompleteByteSlice<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteByteSlice<'a> {
  type Item = u8;
  type RawItem = u8;
  type Iter = Enumerate<Self::IterElem>;
  type IterElem = Map<Iter<'a, Self::Item>, fn(&u8) -> u8>; //Iter<'a, Self::RawItem>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteByteSlice<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteByteSlice(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteByteSlice(left), CompleteByteSlice(right))
  }
}

impl<'a> InputLength for CompleteByteSlice<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b [u8]> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b [u8]> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b [u8]) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteByteSlice<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteByteSlice<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteByteSlice<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteByteSlice<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse_to()
  }
}

impl<'a> Offset for CompleteByteSlice<'a> {
  fn offset(&self, second: &CompleteByteSlice<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteByteSlice<'a> {
  fn as_bytes(&self) -> &[u8] {
    self.0.as_bytes()
  }
}

#[cfg(feature = "std")]
impl<'a> super::util::HexDisplay for CompleteByteSlice<'a> {
  fn to_hex(&self, chunk_size: usize) -> String {
    self.0.to_hex(chunk_size)
  }

  fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
    self.0.to_hex_from(chunk_size, from)
  }
}
<commit_msg>add an Input type with configurable AtEof behaviour<commit_after>//! Custom input types
//!

use traits::{AsBytes, AtEof, Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, Offset, ParseTo, Slice};

use std::str::{self, CharIndices, Chars, FromStr};
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use std::iter::{Enumerate, Map};
use std::slice::Iter;

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct CompleteStr<'a>(pub &'a str);

impl<'a> AtEof for CompleteStr<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteStr<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteStr<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteStr<'a> {
  type Item = char;
  type RawItem = char;
  type Iter = CharIndices<'a>;
  type IterElem = Chars<'a>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteStr<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteStr(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteStr(left), CompleteStr(right))
  }
}

impl<'a> InputLength for CompleteStr<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteStr<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteStr<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteStr<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteStr<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteStr<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteStr<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse().ok()
  }
}

impl<'a> Offset for CompleteStr<'a> {
  fn offset(&self, second: &CompleteStr<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteStr<'a> {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(self.0)
  }
}

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct CompleteByteSlice<'a>(pub &'a [u8]);

impl<'a> AtEof for CompleteByteSlice<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteByteSlice<'a> {
  type Item = u8;
  type RawItem = u8;
  type Iter = Enumerate<Self::IterElem>;
  type IterElem = Map<Iter<'a, Self::Item>, fn(&u8) -> u8>; //Iter<'a, Self::RawItem>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteByteSlice<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteByteSlice(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteByteSlice(left), CompleteByteSlice(right))
  }
}

impl<'a> InputLength for CompleteByteSlice<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b [u8]> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b [u8]> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b [u8]) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteByteSlice<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteByteSlice<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteByteSlice<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteByteSlice<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse_to()
  }
}

impl<'a> Offset for CompleteByteSlice<'a> {
  fn offset(&self, second: &CompleteByteSlice<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteByteSlice<'a> {
  fn as_bytes(&self) -> &[u8] {
    self.0.as_bytes()
  }
}

#[cfg(feature = "std")]
impl<'a> super::util::HexDisplay for CompleteByteSlice<'a> {
  fn to_hex(&self, chunk_size: usize) -> String {
    self.0.to_hex(chunk_size)
  }

  fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
    self.0.to_hex_from(chunk_size, from)
  }
}

#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct Input<T> {
  pub inner:  T,
  pub at_eof: bool,
}

impl<T> AtEof for Input<T> {
  fn at_eof(&self) -> bool {
    self.at_eof
  }
}

impl<T: Slice<Range<usize>>> Slice<Range<usize>> for Input<T> {
  fn slice(&self, range: Range<usize>) -> Self {
    Input {
      inner:  self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeTo<usize>>> Slice<RangeTo<usize>> for Input<T> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    Input {
      inner:  self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeFrom<usize>>> Slice<RangeFrom<usize>> for Input<T> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    Input {
      inner:  self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeFull>> Slice<RangeFull> for Input<T> {
  fn slice(&self, range: RangeFull) -> Self {
    Input {
      inner:  self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: InputIter> InputIter for Input<T> {
  type Item = <T as InputIter>::Item;
  type RawItem = <T as InputIter>::RawItem;
  type Iter = <T as InputIter>::Iter;
  type IterElem = <T as InputIter>::IterElem;

  fn iter_indices(&self) -> Self::Iter {
    self.inner.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.inner.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.inner.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.inner.slice_index(count)
  }
}

impl<T: InputTake> InputTake for Input<T> {
  fn take(&self, count: usize) -> Self {
    Input {
      inner:  self.inner.take(count),
      at_eof: self.at_eof,
    }
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.inner.take_split(count);
    (Input {
      inner:  left,
      at_eof: self.at_eof
    }, Input {
      inner:  right,
      at_eof: self.at_eof
    })
  }
}

impl<T: InputLength> InputLength for Input<T> {
  fn input_len(&self) -> usize {
    self.inner.input_len()
  }
}

impl<'b, T: Compare<&'b str>> Compare<&'b str> for Input<T> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.inner.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.inner.compare_no_case(t)
  }
}

impl<'b, T: FindSubstring<&'b str>> FindSubstring<&'b str> for Input<T> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.inner.find_substring(substr)
  }
}

impl<T: FindToken<char>> FindToken<char> for Input<T> {
  fn find_token(&self, token: char) -> bool {
    self.inner.find_token(token)
  }
}

impl<T: FindToken<u8>> FindToken<u8> for Input<T> {
  fn find_token(&self, token: u8) -> bool {
    self.inner.find_token(token)
  }
}

impl<'a, T: FindToken<&'a u8> > FindToken<&'a u8> for Input<T> {
  fn find_token(&self, token: &'a u8) -> bool {
    self.inner.find_token(token)
  }
}

impl<'a, R: FromStr, T: ParseTo<R>> ParseTo<R> for Input<T> {
  fn parse_to(&self) -> Option<R> {
    self.inner.parse_to()
  }
}

impl<T: Offset> Offset for Input<T> {
  fn offset(&self, second: &Input<T>) -> usize {
    self.inner.offset(&second.inner)
  }
}

impl<T: AsBytes> AsBytes for Input<T>  {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(&self.inner)
  }
}
<|endoftext|>


<commit_before>use bifrost::conshash::weights::Weights;
use bifrost::conshash::ConsistentHashing;
use bifrost::membership::member::MemberService;
use bifrost::membership::server::Membership;
use bifrost::raft;
use bifrost::raft::client::RaftClient;
use bifrost::raft::state_machine::master as sm_master;
use bifrost::rpc;
use bifrost::rpc::Server;
use bifrost::tcp::STANDALONE_ADDRESS_STRING;
use bifrost::utils::fut_exec::wait;
use futures::Future;
use ram::chunk::Chunks;
use ram::cleaner::Cleaner;
use ram::schema::sm as schema_sm;
use ram::schema::LocalSchemasCache;
use ram::types::Id;
use std::io;
use std::sync::Arc;

pub mod cell_rpc;
pub mod transactions;

pub static CONS_HASH_ID: u64 = hash_ident!(NEB_CONSHASH_MEM_WEIGHTS) as u64;

#[derive(Debug)]
pub enum ServerError {
    CannotJoinCluster,
    CannotJoinClusterGroup(sm_master::ExecError),
    CannotInitMemberTable,
    CannotSetServerWeight,
    CannotInitConsistentHashTable,
    CannotLoadMetaClient,
    CannotInitializeSchemaServer(sm_master::ExecError),
    StandaloneMustAlsoBeMetaServer,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerOptions {
    pub chunk_count: usize,
    pub memory_size: usize,
    pub backup_storage: Option<String>,
    pub wal_storage: Option<String>,
}

pub struct ServerMeta {
    pub schemas: LocalSchemasCache,
}

pub struct NebServer {
    pub chunks: Arc<Chunks>,
    pub meta: Arc<ServerMeta>,
    pub rpc: Arc<rpc::Server>,
    pub consh: Arc<ConsistentHashing>,
    pub member_pool: rpc::ClientPool,
    pub txn_peer: transactions::Peer,
    pub raft_service: Option<Arc<raft::RaftService>>,
    pub server_id: u64,
    pub cleaner: Cleaner,
}

pub fn init_conshash(
    group_name: &String,
    address: &String,
    memory_size: u64,
    raft_client: &Arc<RaftClient>,
) -> Result<Arc<ConsistentHashing>, ServerError> {
    match ConsistentHashing::new_with_id(CONS_HASH_ID, group_name, raft_client) {
        Ok(ch) => {
            wait(ch.set_weight(address, memory_size));
            if !ch.init_table().is_ok() {
                error!("Cannot initialize member table");
                return Err(ServerError::CannotInitMemberTable);
            }
            return Ok(ch);
        }
        _ => {
            error!("Cannot initialize consistent hash table");
            return Err(ServerError::CannotInitConsistentHashTable);
        }
    }
}

impl NebServer {
    pub fn new(
        opts: &ServerOptions,
        server_addr: &String,
        group_name: &String,
        rpc_server: &Arc<rpc::Server>,
        raft_service: &Option<Arc<raft::RaftService>>,
        raft_client: &Arc<RaftClient>,
    ) -> Result<Arc<NebServer>, ServerError> {
        debug!(
            "Creating key-value server instance, group name {}",
            group_name
        );
        if let &Some(ref raft_service) = raft_service {
            raft_service.register_state_machine(Box::new(schema_sm::SchemasSM::new(
                group_name,
                raft_service,
            )));
            Weights::new_with_id(CONS_HASH_ID, raft_service);
        }
        let schemas = LocalSchemasCache::new(group_name, Some(raft_client)).unwrap();
        let meta_rc = Arc::new(ServerMeta { schemas });
        let chunks = Chunks::new(
            opts.chunk_count,
            opts.memory_size,
            meta_rc.clone(),
            opts.backup_storage.clone(),
            opts.wal_storage.clone(),
        );
        let cleaner = Cleaner::new_and_start(chunks.clone());
        let conshasing = init_conshash(
            group_name,
            server_addr,
            opts.memory_size as u64,
            raft_client,
        )?;
        let server = Arc::new(NebServer {
            chunks,
            cleaner,
            meta: meta_rc,
            rpc: rpc_server.clone(),
            consh: conshasing.clone(),
            member_pool: rpc::ClientPool::new(),
            txn_peer: transactions::Peer::new(server_addr),
            raft_service: raft_service.clone(),
            server_id: rpc_server.server_id,
        });
        rpc_server.register_service(
            cell_rpc::DEFAULT_SERVICE_ID,
            &cell_rpc::NebRPCService::new(&server),
        );
        rpc_server.register_service(
            transactions::manager::DEFAULT_SERVICE_ID,
            &transactions::manager::TransactionManager::new(&server),
        );
        rpc_server.register_service(
            transactions::data_site::DEFAULT_SERVICE_ID,
            &transactions::data_site::DataManager::new(&server),
        );
        Ok(server)
    }

    pub fn new_from_opts<'a>(
        opts: &ServerOptions,
        server_addr: &'a str,
        group_name: &'a str,
    ) -> Arc<NebServer> {
        debug!("Creating key-value server from options");
        let group_name = &String::from(group_name);
        let server_addr = &String::from(server_addr);
        let rpc_server = rpc::Server::new(server_addr);
        let meta_mambers = &vec![server_addr.to_owned()];
        let raft_service = raft::RaftService::new(raft::Options {
            storage: raft::Storage::MEMORY,
            address: server_addr.to_owned(),
            service_id: raft::DEFAULT_SERVICE_ID,
        });
        Server::listen_and_resume(&rpc_server);
        rpc_server.register_service(raft::DEFAULT_SERVICE_ID, &raft_service);
        raft::RaftService::start(&raft_service);
        match raft_service.join(meta_mambers) {
            Err(sm_master::ExecError::CannotConstructClient) => {
                info!("Cannot join meta cluster, will bootstrap one.");
                raft_service.bootstrap();
            }
            Ok(Ok(())) => {
                info!(
                    "Joined meta cluster, number of members: {}",
                    raft_service.num_members()
                );
            }
            e => {
                error!("Cannot join into cluster: {:?}", e);
                panic!("{:?}", ServerError::CannotJoinCluster)
            }
        }
        Membership::new(&rpc_server, &raft_service);
        let raft_client = RaftClient::new(meta_mambers, raft::DEFAULT_SERVICE_ID).unwrap();
        RaftClient::prepare_subscription(&rpc_server);
        let member_service = MemberService::new(server_addr, &raft_client);
        wait(member_service.join_group(group_name)).unwrap();
        NebServer::new(
            opts,
            server_addr,
            group_name,
            &rpc_server,
            &Some(raft_service),
            &raft_client,
        )
        .unwrap()
    }

    pub fn get_server_id_by_id(&self, id: &Id) -> Option<u64> {
        if let Some(server_id) = self.consh.get_server_id(id.higher) {
            Some(server_id)
        } else {
            None
        }
    }
    pub fn get_member_by_server_id(&self, server_id: u64) -> io::Result<Arc<rpc::RPCClient>> {
        self.member_pool
            .get_by_id(server_id, |_| self.consh.to_server_name(server_id))
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use client;
    use dovahkiin::types::custom_types::id::Id;
    use dovahkiin::types::custom_types::map::Map;
    use dovahkiin::types::type_id_of;
    use futures::Future;
    use ram::cell::Cell;
    use ram::schema::Field;
    use ram::schema::Schema;
    use server::NebServer;
    use server::ServerOptions;
    use std::sync::Arc;
    use test::Bencher;
    use ram::types::*;

    #[bench]
    fn wr(b: &mut Bencher) {
        const DATA: &'static str = "DATA";
        env_logger::init();
        let server_addr = String::from("127.0.0.1:5302");
        let server_group = String::from("bench_test");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 512 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let schema_id = 123;
        let schema = Schema {
            id: schema_id,
            name: String::from("schema"),
            key_field: None,
            str_key_field: None,
            is_dynamic: false,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new(
                    DATA,
                    type_id_of(Type::U64),
                    false,
                    false,
                    None,
                )]),
            ),
        };

        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], &server_group).unwrap(),
        );
        client.new_schema_with_id(schema).wait();

        let id = Id::new(0, 1);
        let mut value = Value::Map(Map::new());
        value[DATA] = Value::U64(2);
        let cell = Cell::new_with_id(schema_id, &id, value);
        b.iter(|| {
            client.upsert_cell(cell.clone()).wait();
        })
    }

    #[bench]
    fn txn(b: &mut Bencher) {
        const DATA: &'static str = "DATA";
        env_logger::init();
        let server_addr = String::from("127.0.0.1:5303");
        let server_group = String::from("bench_test");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 512 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let schema_id = 123;
        let schema = Schema {
            id: schema_id,
            name: String::from("schema"),
            key_field: None,
            str_key_field: None,
            is_dynamic: false,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new(
                    DATA,
                    type_id_of(Type::U64),
                    false,
                    false,
                    None,
                )]),
            ),
        };

        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], &server_group).unwrap(),
        );
        client.new_schema_with_id(schema).wait();
        b.iter(|| {
            client.transaction(move |txn| {
                let id = Id::new(0, 1);
                let mut value = Value::Map(Map::new());
                value[DATA] = Value::U64(2);
                let cell = Cell::new_with_id(schema_id, &id, value);
                txn.upsert(cell)
            }).wait()
        })
    }

    #[bench]
    fn cell_construct(b: &mut Bencher) {
        b.iter(|| {
            let id = Id::new(0, 1);
            let mut value = Value::Map(Map::new());
            value["DATA"] = Value::U64(2);
            Cell::new_with_id(1, &id, value);
        })
    }
}
<commit_msg>bench cell clone<commit_after>use bifrost::conshash::weights::Weights;
use bifrost::conshash::ConsistentHashing;
use bifrost::membership::member::MemberService;
use bifrost::membership::server::Membership;
use bifrost::raft;
use bifrost::raft::client::RaftClient;
use bifrost::raft::state_machine::master as sm_master;
use bifrost::rpc;
use bifrost::rpc::Server;
use bifrost::tcp::STANDALONE_ADDRESS_STRING;
use bifrost::utils::fut_exec::wait;
use futures::Future;
use ram::chunk::Chunks;
use ram::cleaner::Cleaner;
use ram::schema::sm as schema_sm;
use ram::schema::LocalSchemasCache;
use ram::types::Id;
use std::io;
use std::sync::Arc;

pub mod cell_rpc;
pub mod transactions;

pub static CONS_HASH_ID: u64 = hash_ident!(NEB_CONSHASH_MEM_WEIGHTS) as u64;

#[derive(Debug)]
pub enum ServerError {
    CannotJoinCluster,
    CannotJoinClusterGroup(sm_master::ExecError),
    CannotInitMemberTable,
    CannotSetServerWeight,
    CannotInitConsistentHashTable,
    CannotLoadMetaClient,
    CannotInitializeSchemaServer(sm_master::ExecError),
    StandaloneMustAlsoBeMetaServer,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerOptions {
    pub chunk_count: usize,
    pub memory_size: usize,
    pub backup_storage: Option<String>,
    pub wal_storage: Option<String>,
}

pub struct ServerMeta {
    pub schemas: LocalSchemasCache,
}

pub struct NebServer {
    pub chunks: Arc<Chunks>,
    pub meta: Arc<ServerMeta>,
    pub rpc: Arc<rpc::Server>,
    pub consh: Arc<ConsistentHashing>,
    pub member_pool: rpc::ClientPool,
    pub txn_peer: transactions::Peer,
    pub raft_service: Option<Arc<raft::RaftService>>,
    pub server_id: u64,
    pub cleaner: Cleaner,
}

pub fn init_conshash(
    group_name: &String,
    address: &String,
    memory_size: u64,
    raft_client: &Arc<RaftClient>,
) -> Result<Arc<ConsistentHashing>, ServerError> {
    match ConsistentHashing::new_with_id(CONS_HASH_ID, group_name, raft_client) {
        Ok(ch) => {
            wait(ch.set_weight(address, memory_size));
            if !ch.init_table().is_ok() {
                error!("Cannot initialize member table");
                return Err(ServerError::CannotInitMemberTable);
            }
            return Ok(ch);
        }
        _ => {
            error!("Cannot initialize consistent hash table");
            return Err(ServerError::CannotInitConsistentHashTable);
        }
    }
}

impl NebServer {
    pub fn new(
        opts: &ServerOptions,
        server_addr: &String,
        group_name: &String,
        rpc_server: &Arc<rpc::Server>,
        raft_service: &Option<Arc<raft::RaftService>>,
        raft_client: &Arc<RaftClient>,
    ) -> Result<Arc<NebServer>, ServerError> {
        debug!(
            "Creating key-value server instance, group name {}",
            group_name
        );
        if let &Some(ref raft_service) = raft_service {
            raft_service.register_state_machine(Box::new(schema_sm::SchemasSM::new(
                group_name,
                raft_service,
            )));
            Weights::new_with_id(CONS_HASH_ID, raft_service);
        }
        let schemas = LocalSchemasCache::new(group_name, Some(raft_client)).unwrap();
        let meta_rc = Arc::new(ServerMeta { schemas });
        let chunks = Chunks::new(
            opts.chunk_count,
            opts.memory_size,
            meta_rc.clone(),
            opts.backup_storage.clone(),
            opts.wal_storage.clone(),
        );
        let cleaner = Cleaner::new_and_start(chunks.clone());
        let conshasing = init_conshash(
            group_name,
            server_addr,
            opts.memory_size as u64,
            raft_client,
        )?;
        let server = Arc::new(NebServer {
            chunks,
            cleaner,
            meta: meta_rc,
            rpc: rpc_server.clone(),
            consh: conshasing.clone(),
            member_pool: rpc::ClientPool::new(),
            txn_peer: transactions::Peer::new(server_addr),
            raft_service: raft_service.clone(),
            server_id: rpc_server.server_id,
        });
        rpc_server.register_service(
            cell_rpc::DEFAULT_SERVICE_ID,
            &cell_rpc::NebRPCService::new(&server),
        );
        rpc_server.register_service(
            transactions::manager::DEFAULT_SERVICE_ID,
            &transactions::manager::TransactionManager::new(&server),
        );
        rpc_server.register_service(
            transactions::data_site::DEFAULT_SERVICE_ID,
            &transactions::data_site::DataManager::new(&server),
        );
        Ok(server)
    }

    pub fn new_from_opts<'a>(
        opts: &ServerOptions,
        server_addr: &'a str,
        group_name: &'a str,
    ) -> Arc<NebServer> {
        debug!("Creating key-value server from options");
        let group_name = &String::from(group_name);
        let server_addr = &String::from(server_addr);
        let rpc_server = rpc::Server::new(server_addr);
        let meta_mambers = &vec![server_addr.to_owned()];
        let raft_service = raft::RaftService::new(raft::Options {
            storage: raft::Storage::MEMORY,
            address: server_addr.to_owned(),
            service_id: raft::DEFAULT_SERVICE_ID,
        });
        Server::listen_and_resume(&rpc_server);
        rpc_server.register_service(raft::DEFAULT_SERVICE_ID, &raft_service);
        raft::RaftService::start(&raft_service);
        match raft_service.join(meta_mambers) {
            Err(sm_master::ExecError::CannotConstructClient) => {
                info!("Cannot join meta cluster, will bootstrap one.");
                raft_service.bootstrap();
            }
            Ok(Ok(())) => {
                info!(
                    "Joined meta cluster, number of members: {}",
                    raft_service.num_members()
                );
            }
            e => {
                error!("Cannot join into cluster: {:?}", e);
                panic!("{:?}", ServerError::CannotJoinCluster)
            }
        }
        Membership::new(&rpc_server, &raft_service);
        let raft_client = RaftClient::new(meta_mambers, raft::DEFAULT_SERVICE_ID).unwrap();
        RaftClient::prepare_subscription(&rpc_server);
        let member_service = MemberService::new(server_addr, &raft_client);
        wait(member_service.join_group(group_name)).unwrap();
        NebServer::new(
            opts,
            server_addr,
            group_name,
            &rpc_server,
            &Some(raft_service),
            &raft_client,
        )
        .unwrap()
    }

    pub fn get_server_id_by_id(&self, id: &Id) -> Option<u64> {
        if let Some(server_id) = self.consh.get_server_id(id.higher) {
            Some(server_id)
        } else {
            None
        }
    }
    pub fn get_member_by_server_id(&self, server_id: u64) -> io::Result<Arc<rpc::RPCClient>> {
        self.member_pool
            .get_by_id(server_id, |_| self.consh.to_server_name(server_id))
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use client;
    use dovahkiin::types::custom_types::id::Id;
    use dovahkiin::types::custom_types::map::Map;
    use dovahkiin::types::type_id_of;
    use futures::Future;
    use ram::cell::Cell;
    use ram::schema::Field;
    use ram::schema::Schema;
    use server::NebServer;
    use server::ServerOptions;
    use std::sync::Arc;
    use test::Bencher;
    use ram::types::*;

    #[bench]
    fn wr(b: &mut Bencher) {
        const DATA: &'static str = "DATA";
        env_logger::init();
        let server_addr = String::from("127.0.0.1:5302");
        let server_group = String::from("bench_test");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 512 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let schema_id = 123;
        let schema = Schema {
            id: schema_id,
            name: String::from("schema"),
            key_field: None,
            str_key_field: None,
            is_dynamic: false,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new(
                    DATA,
                    type_id_of(Type::U64),
                    false,
                    false,
                    None,
                )]),
            ),
        };

        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], &server_group).unwrap(),
        );
        client.new_schema_with_id(schema).wait();

        let id = Id::new(0, 1);
        let mut value = Value::Map(Map::new());
        value[DATA] = Value::U64(2);
        let cell = Cell::new_with_id(schema_id, &id, value);
        b.iter(|| {
            client.upsert_cell(cell.clone()).wait();
        })
    }

    #[bench]
    fn txn(b: &mut Bencher) {
        const DATA: &'static str = "DATA";
        env_logger::init();
        let server_addr = String::from("127.0.0.1:5303");
        let server_group = String::from("bench_test");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 512 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let schema_id = 123;
        let schema = Schema {
            id: schema_id,
            name: String::from("schema"),
            key_field: None,
            str_key_field: None,
            is_dynamic: false,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new(
                    DATA,
                    type_id_of(Type::U64),
                    false,
                    false,
                    None,
                )]),
            ),
        };

        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], &server_group).unwrap(),
        );
        client.new_schema_with_id(schema).wait();
        b.iter(|| {
            client.transaction(move |txn| {
                let id = Id::new(0, 1);
                let mut value = Value::Map(Map::new());
                value[DATA] = Value::U64(2);
                let cell = Cell::new_with_id(schema_id, &id, value);
                txn.upsert(cell)
            }).wait()
        })
    }

    #[bench]
    fn cell_construct(b: &mut Bencher) {
        b.iter(|| {
            let id = Id::new(0, 1);
            let mut value = Value::Map(Map::new());
            value["DATA"] = Value::U64(2);
            Cell::new_with_id(1, &id, value);
        })
    }

    #[bench]
    fn cell_clone(b: &mut Bencher) {
        let id = Id::new(0, 1);
        let mut value = Value::Map(Map::new());
        value["DATA"] = Value::U64(2);
        let cell = Cell::new_with_id(1, &id, value);
        b.iter(|| {
            cell.clone();
        })
    }
}
<|endoftext|>


<commit_before>//! This module implements a synchronous transport over a raw TcpListener.

use std::os::unix::net::UnixStream;
use std::{error, fmt, io, path, time};

use serde;
use serde_json;

use crate::client::Transport;
use crate::{Request, Response};

/// Error that can occur while using the UDS transport.
#[derive(Debug)]
pub enum Error {
    /// An error occurred on the socket layer
    SocketError(io::Error),
    /// We didn't receive a complete response till the deadline ran out
    Timeout,
    /// JSON parsing error.
    Json(serde_json::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::SocketError(ref e) => write!(f, "Couldn't connect to host: {}", e),
            Error::Timeout => f.write_str("Didn't receive response data in time, timed out."),
            Error::Json(ref e) => write!(f, "JSON error: {}", e),
        }
    }
}

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

        match *self {
            SocketError(ref e) => Some(e),
            Timeout => None,
            Json(ref e) => Some(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::SocketError(e)
    }
}

impl From<serde_json::Error> for Error {
    fn from(e: serde_json::Error) -> Self {
        Error::Json(e)
    }
}

impl From<Error> for crate::error::Error {
    fn from(e: Error) -> crate::error::Error {
        match e {
            Error::Json(e) => crate::error::Error::Json(e),
            e => crate::error::Error::Transport(Box::new(e)),
        }
    }
}

/// Simple synchronous UDS transport.
#[derive(Debug, Clone)]
pub struct UdsTransport {
    /// The path to the Unix Domain Socket
    pub sockpath: path::PathBuf,
    /// The read and write timeout to use
    pub timeout: Option<time::Duration>,
}

impl UdsTransport {
    /// Create a new UdsTransport without timeouts to use
    pub fn new<P: AsRef<path::Path>>(sockpath: P) -> UdsTransport {
        UdsTransport {
            sockpath: sockpath.as_ref().to_path_buf(),
            timeout: None,
        }
    }

    fn request<R>(&self, req: impl serde::Serialize) -> Result<R, Error>
    where
        R: for<'a> serde::de::Deserialize<'a>,
    {
        let mut sock = UnixStream::connect(&self.sockpath)?;
        sock.set_read_timeout(self.timeout)?;
        sock.set_write_timeout(self.timeout)?;

        serde_json::to_writer(&mut sock, &req)?;

        // NOTE: we don't check the id there, so it *must* be synchronous
        let resp: R = serde_json::Deserializer::from_reader(&mut sock)
            .into_iter()
            .next()
            .ok_or(Error::Timeout)??;
        Ok(resp)
    }
}

impl Transport for UdsTransport {
    fn send_request(&self, req: Request) -> Result<Response, crate::error::Error> {
        Ok(self.request(req)?)
    }

    fn send_batch(&self, reqs: &[Request]) -> Result<Vec<Response>, crate::error::Error> {
        Ok(self.request(reqs)?)
    }

    fn fmt_target(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.sockpath.to_string_lossy())
    }
}

#[cfg(test)]
mod tests {
    use std::{
        fs,
        io::{Read, Write},
        os::unix::net::UnixListener,
        process,
        thread,
    };

    use super::*;
    use crate::Client;

    // Test a dummy request / response over an UDS
    #[test]
    fn sanity_check_uds_transport() {
        let socket_path: path::PathBuf = format!("uds_scratch_{}.socket", process::id()).into();
        // Any leftover?
        fs::remove_file(&socket_path).unwrap_or(());

        let server = UnixListener::bind(&socket_path).unwrap();
        let dummy_req = Request {
            method: "getinfo",
            params: &[],
            id: serde_json::Value::Number(111.into()),
            jsonrpc: Some("2.0".into()),
        };
        let dummy_req_ser = serde_json::to_vec(&dummy_req).unwrap();
        let dummy_resp = Response {
            result: None,
            error: None,
            id: serde_json::Value::Number(111.into()),
            jsonrpc: Some("2.0".into()),
        };
        let dummy_resp_ser = serde_json::to_vec(&dummy_resp).unwrap();

        let cli_socket_path = socket_path.clone();
        let client_thread = thread::spawn(move || {
            let transport = UdsTransport {
                sockpath: cli_socket_path,
                timeout: Some(time::Duration::from_secs(5)),
            };
            let client = Client::with_transport(transport);

            client.send_request(dummy_req.clone()).unwrap()
        });

        let (mut stream, _) = server.accept().unwrap();
        stream.set_read_timeout(Some(time::Duration::from_secs(5))).unwrap();
        let mut recv_req = vec![0; dummy_req_ser.len()];
        let mut read = 0;
        while read < dummy_req_ser.len() {
            read += stream.read(&mut recv_req[read..]).unwrap();
        }
        assert_eq!(recv_req, dummy_req_ser);

        stream.write_all(&dummy_resp_ser).unwrap();
        stream.flush().unwrap();
        let recv_resp = client_thread.join().unwrap();
        assert_eq!(serde_json::to_vec(&recv_resp).unwrap(), dummy_resp_ser);

        // Clean up
        drop(server);
        fs::remove_file(&socket_path).unwrap();
    }
}
<commit_msg>Remove useless conversion<commit_after>//! This module implements a synchronous transport over a raw TcpListener.

use std::os::unix::net::UnixStream;
use std::{error, fmt, io, path, time};

use serde;
use serde_json;

use crate::client::Transport;
use crate::{Request, Response};

/// Error that can occur while using the UDS transport.
#[derive(Debug)]
pub enum Error {
    /// An error occurred on the socket layer
    SocketError(io::Error),
    /// We didn't receive a complete response till the deadline ran out
    Timeout,
    /// JSON parsing error.
    Json(serde_json::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::SocketError(ref e) => write!(f, "Couldn't connect to host: {}", e),
            Error::Timeout => f.write_str("Didn't receive response data in time, timed out."),
            Error::Json(ref e) => write!(f, "JSON error: {}", e),
        }
    }
}

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

        match *self {
            SocketError(ref e) => Some(e),
            Timeout => None,
            Json(ref e) => Some(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::SocketError(e)
    }
}

impl From<serde_json::Error> for Error {
    fn from(e: serde_json::Error) -> Self {
        Error::Json(e)
    }
}

impl From<Error> for crate::error::Error {
    fn from(e: Error) -> crate::error::Error {
        match e {
            Error::Json(e) => crate::error::Error::Json(e),
            e => crate::error::Error::Transport(Box::new(e)),
        }
    }
}

/// Simple synchronous UDS transport.
#[derive(Debug, Clone)]
pub struct UdsTransport {
    /// The path to the Unix Domain Socket
    pub sockpath: path::PathBuf,
    /// The read and write timeout to use
    pub timeout: Option<time::Duration>,
}

impl UdsTransport {
    /// Create a new UdsTransport without timeouts to use
    pub fn new<P: AsRef<path::Path>>(sockpath: P) -> UdsTransport {
        UdsTransport {
            sockpath: sockpath.as_ref().to_path_buf(),
            timeout: None,
        }
    }

    fn request<R>(&self, req: impl serde::Serialize) -> Result<R, Error>
    where
        R: for<'a> serde::de::Deserialize<'a>,
    {
        let mut sock = UnixStream::connect(&self.sockpath)?;
        sock.set_read_timeout(self.timeout)?;
        sock.set_write_timeout(self.timeout)?;

        serde_json::to_writer(&mut sock, &req)?;

        // NOTE: we don't check the id there, so it *must* be synchronous
        let resp: R = serde_json::Deserializer::from_reader(&mut sock)
            .into_iter()
            .next()
            .ok_or(Error::Timeout)??;
        Ok(resp)
    }
}

impl Transport for UdsTransport {
    fn send_request(&self, req: Request) -> Result<Response, crate::error::Error> {
        Ok(self.request(req)?)
    }

    fn send_batch(&self, reqs: &[Request]) -> Result<Vec<Response>, crate::error::Error> {
        Ok(self.request(reqs)?)
    }

    fn fmt_target(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.sockpath.to_string_lossy())
    }
}

#[cfg(test)]
mod tests {
    use std::{
        fs,
        io::{Read, Write},
        os::unix::net::UnixListener,
        process,
        thread,
    };

    use super::*;
    use crate::Client;

    // Test a dummy request / response over an UDS
    #[test]
    fn sanity_check_uds_transport() {
        let socket_path: path::PathBuf = format!("uds_scratch_{}.socket", process::id()).into();
        // Any leftover?
        fs::remove_file(&socket_path).unwrap_or(());

        let server = UnixListener::bind(&socket_path).unwrap();
        let dummy_req = Request {
            method: "getinfo",
            params: &[],
            id: serde_json::Value::Number(111.into()),
            jsonrpc: Some("2.0"),
        };
        let dummy_req_ser = serde_json::to_vec(&dummy_req).unwrap();
        let dummy_resp = Response {
            result: None,
            error: None,
            id: serde_json::Value::Number(111.into()),
            jsonrpc: Some("2.0".into()),
        };
        let dummy_resp_ser = serde_json::to_vec(&dummy_resp).unwrap();

        let cli_socket_path = socket_path.clone();
        let client_thread = thread::spawn(move || {
            let transport = UdsTransport {
                sockpath: cli_socket_path,
                timeout: Some(time::Duration::from_secs(5)),
            };
            let client = Client::with_transport(transport);

            client.send_request(dummy_req.clone()).unwrap()
        });

        let (mut stream, _) = server.accept().unwrap();
        stream.set_read_timeout(Some(time::Duration::from_secs(5))).unwrap();
        let mut recv_req = vec![0; dummy_req_ser.len()];
        let mut read = 0;
        while read < dummy_req_ser.len() {
            read += stream.read(&mut recv_req[read..]).unwrap();
        }
        assert_eq!(recv_req, dummy_req_ser);

        stream.write_all(&dummy_resp_ser).unwrap();
        stream.flush().unwrap();
        let recv_resp = client_thread.join().unwrap();
        assert_eq!(serde_json::to_vec(&recv_resp).unwrap(), dummy_resp_ser);

        // Clean up
        drop(server);
        fs::remove_file(&socket_path).unwrap();
    }
}
<|endoftext|>


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

use std::process::Command;
use libc;

pub fn is_root() -> bool {
    unsafe { libc::geteuid() == 0 }
}

pub fn enable_ipv4_forwarding() -> Result<(), String> {
    let sysctl_arg = if cfg!(target_os = "linux") {
        "net.ipv4.ip_forward=1"
    } else if cfg!(target_os = "macos") {
        "net.inet.ip.forwarding=1"
    } else {
        unimplemented!()
    };
    let status = Command::new("sysctl")
        .arg("-w")
        .arg(sysctl_arg)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("sysctl: {}", status))
    }
}

#[test]
fn enable_ipv4_forwarding_test() {
    enable_ipv4_forwarding().unwrap();
}

pub enum RouteType {
    Net,
    Host,
}

pub struct DefaultGateway {
    origin: String,
    remote: String,
}

impl DefaultGateway {
    pub fn create(gateway: &str, remote: &str) -> DefaultGateway {
        let origin = get_default_gateway().unwrap();
        add_route(RouteType::Host, remote, &origin).unwrap();
        delete_default_gateway().unwrap();
        set_default_gateway(gateway).unwrap();
        DefaultGateway {
            origin: origin,
            remote: String::from(remote),
        }
    }
}

impl Drop for DefaultGateway {
    fn drop(&mut self) {
        delete_default_gateway().unwrap();
        set_default_gateway(&self.origin).unwrap();
        delete_route(RouteType::Host, &self.remote).unwrap();
    }
}

pub fn delete_route(route_type: RouteType, route: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    let status = if cfg!(target_os = "linux") {
        Command::new("route")
            .arg("-n")
            .arg("del")
            .arg(mode)
            .arg(route)
            .status()
            .unwrap()
    } else if cfg!(target_os = "macos") {
        Command::new("route")
            .arg("-n")
            .arg("delete")
            .arg(mode)
            .arg(route)
            .status()
            .unwrap()
    } else {
        unimplemented!()
    };
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn add_route(route_type: RouteType, route: &str, gateway: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    let status = if cfg!(target_os = "linux") {
        Command::new("route")
            .arg("-n")
            .arg("add")
            .arg(mode)
            .arg(route)
            .arg("gw")
            .arg(gateway)
            .status()
            .unwrap()
    } else if cfg!(target_os = "macos") {
        Command::new("route")
            .arg("-n")
            .arg("add")
            .arg(mode)
            .arg(route)
            .arg(gateway)
            .status()
            .unwrap()
    } else {
        unimplemented!()
    };
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn set_default_gateway(gateway: &str) -> Result<(), String> {
    add_route(RouteType::Net, "default", gateway)
}

pub fn delete_default_gateway() -> Result<(), String> {
    delete_route(RouteType::Net, "default")
}

pub fn get_default_gateway() -> Result<String, String> {
    let cmd = if cfg!(target_os = "linux") {
        "ip -4 route list 0/0 | awk '{print $3}'"
    } else if cfg!(target_os = "macos") {
        "route -n get default | grep gateway | awk '{print $2}'"
    } else {
        unimplemented!()
    };
    let output = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .output()
        .unwrap();
    if output.status.success() {
        Ok(String::from_utf8(output.stdout).unwrap())
    } else {
        Err(String::from_utf8(output.stderr).unwrap())
    }
}

#[test]
fn get_default_gateway_test() {
    get_default_gateway().unwrap();
}

#[test]
fn route_test() {
    assert!(is_root());

    let gw = get_default_gateway().unwrap();
    add_route(RouteType::Host, "1.1.1.1", &gw).unwrap();
    delete_route(RouteType::Host, "1.1.1.1").unwrap();
}
<commit_msg>Add more verbose logging<commit_after>// Copyright 2016-2017 Chang Lan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::process::Command;
use libc;

pub fn is_root() -> bool {
    unsafe { libc::geteuid() == 0 }
}

pub fn enable_ipv4_forwarding() -> Result<(), String> {
    let sysctl_arg = if cfg!(target_os = "linux") {
        "net.ipv4.ip_forward=1"
    } else if cfg!(target_os = "macos") {
        "net.inet.ip.forwarding=1"
    } else {
        unimplemented!()
    };
    info!("Enabling IPv4 Forwarding.");
    let status = Command::new("sysctl")
        .arg("-w")
        .arg(sysctl_arg)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("sysctl: {}", status))
    }
}

#[test]
fn enable_ipv4_forwarding_test() {
    enable_ipv4_forwarding().unwrap();
}

pub enum RouteType {
    Net,
    Host,
}

pub struct DefaultGateway {
    origin: String,
    remote: String,
}

impl DefaultGateway {
    pub fn create(gateway: &str, remote: &str) -> DefaultGateway {
        let origin = get_default_gateway().unwrap();
        info!("Original default gateway: {}.", origin);
        add_route(RouteType::Host, remote, &origin).unwrap();
        delete_default_gateway().unwrap();
        set_default_gateway(gateway).unwrap();
        DefaultGateway {
            origin: origin,
            remote: String::from(remote),
        }
    }
}

impl Drop for DefaultGateway {
    fn drop(&mut self) {
        delete_default_gateway().unwrap();
        set_default_gateway(&self.origin).unwrap();
        delete_route(RouteType::Host, &self.remote).unwrap();
    }
}

pub fn delete_route(route_type: RouteType, route: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    info!("Deleting route: {} {}.", mode, route);
    let status = if cfg!(target_os = "linux") {
        Command::new("route")
            .arg("-n")
            .arg("del")
            .arg(mode)
            .arg(route)
            .status()
            .unwrap()
    } else if cfg!(target_os = "macos") {
        Command::new("route")
            .arg("-n")
            .arg("delete")
            .arg(mode)
            .arg(route)
            .status()
            .unwrap()
    } else {
        unimplemented!()
    };
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn add_route(route_type: RouteType, route: &str, gateway: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    info!("Adding route: {} {} gateway {}.", mode, route, gateway);
    let status = if cfg!(target_os = "linux") {
        Command::new("route")
            .arg("-n")
            .arg("add")
            .arg(mode)
            .arg(route)
            .arg("gw")
            .arg(gateway)
            .status()
            .unwrap()
    } else if cfg!(target_os = "macos") {
        Command::new("route")
            .arg("-n")
            .arg("add")
            .arg(mode)
            .arg(route)
            .arg(gateway)
            .status()
            .unwrap()
    } else {
        unimplemented!()
    };
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn set_default_gateway(gateway: &str) -> Result<(), String> {
    add_route(RouteType::Net, "default", gateway)
}

pub fn delete_default_gateway() -> Result<(), String> {
    delete_route(RouteType::Net, "default")
}

pub fn get_default_gateway() -> Result<String, String> {
    let cmd = if cfg!(target_os = "linux") {
        "ip -4 route list 0/0 | awk '{print $3}'"
    } else if cfg!(target_os = "macos") {
        "route -n get default | grep gateway | awk '{print $2}'"
    } else {
        unimplemented!()
    };
    let output = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .output()
        .unwrap();
    if output.status.success() {
        Ok(String::from_utf8(output.stdout).unwrap().trim_right().to_string())
    } else {
        Err(String::from_utf8(output.stderr).unwrap())
    }
}

#[test]
fn get_default_gateway_test() {
    get_default_gateway().unwrap();
}

#[test]
fn route_test() {
    assert!(is_root());

    let gw = get_default_gateway().unwrap();
    add_route(RouteType::Host, "1.1.1.1", &gw).unwrap();
    delete_route(RouteType::Host, "1.1.1.1").unwrap();
}
<|endoftext|>


<commit_before>//! Types representing for data which will be retrieved from the driver.
//! Currently this data is expected to look like a JSON object but this may be
//! changed in the future. Driver authors must cast the data they retrieve from
//! the driver to these types.

use linear_map::LinearMap;

/// The atomic level of a pointer.
pub type Key = String;

/// Represents a JSON pointer to a document property.
pub type Pointer = Vec<Key>;

/// Various value types. Based on types in the [JSON standard][1] (see section
/// 5).
///
/// [1]: http://ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
#[derive(PartialEq, Clone, Debug)]
pub enum Value {
  /// The abscense of any value.
  Null,
  /// True or false.
  Boolean(bool),
  /// An integer numeric value.
  I64(i64),
  /// A floating point numeric value.
  F64(f64),
  /// A list of characters.
  String(String),
  /// A map of key/value pairs. Backed by a linear map to maintain order and
  /// have high performance for small objects.
  Object(LinearMap<Key, Value>),
  /// A list of values. Just a value, but using *only* integer keys.
  Array(Vec<Value>)
}

impl Value {
  /// Gets a value at a specific point. Helpful for retrieving nested values.
  pub fn get(&self, mut pointer: Pointer) -> Option<Value> {
    match *self {
      Value::Object(ref map) => {
        if pointer.is_empty() {
          Some(self.clone())
        } else if let Some(value) = map.get(&pointer.remove(0)) {
          value.get(pointer)
        } else {
          None
        }
      },
      Value::Array(ref vec) => {
        if pointer.is_empty() {
          Some(self.clone())
        } else if let Some(value) = pointer.remove(0).parse::<usize>().ok().map_or(None, |i| vec.get(i)) {
          value.get(pointer)
        } else {
          None
        }
      },
      _ => if pointer.is_empty() { Some(self.clone()) } else { None }
    }
  }

  /// Converts a value into a JSON string for distribution.
  pub fn to_json(&self) -> String {
    match *self {
      Value::Null => "null".to_owned(),
      Value::Boolean(value) => if value { "true".to_owned() } else { "false".to_owned() },
      Value::I64(value) => value.to_string(),
      Value::F64(value) => value.to_string(),
      Value::String(ref value) => "\"".to_owned() + &escape_string_for_json(value) + "\"",
      Value::Object(ref map) => {
        let mut json = "{".to_owned();
        for (key, value) in map {
          json.push_str("\"");
          json.push_str(&escape_string_for_json(key));
          json.push_str("\":");
          json.push_str(&value.to_json());
          json.push_str(",");
        }
        // Remove the last comma.
        json.pop();
        json.push_str("}");
        json
      },
      Value::Array(ref vec) => {
        let mut json = "[".to_owned();
        for item in vec {
          json.push_str(&item.to_json());
          json.push_str(",");
        }
        // Remove the last comma.
        json.pop();
        json.push_str("]");
        json
      }
    }
  }
}

/// Takes a string and escapes it for use within a JSON encoded object. Read,
/// inside quotes.
fn escape_string_for_json(string: &str) -> String {
  string.replace("\"", "\\\"").replace("\n", "\\n")
}

/// An iterator of values. Used by drivers to convert their own iterator
/// implementations into a single type.
pub struct ValueIter<'a> {
  iter: Box<Iterator<Item=Value> + 'a>
}

impl<'a> ValueIter<'a> {
  /// Create a new value iterator.
  pub fn new<I>(iter: I) -> Self where I: Iterator<Item=Value> + 'a {
    ValueIter {
      iter: Box::new(iter)
    }
  }
}

impl<'a> Iterator for ValueIter<'a> {
  type Item = Value;

  #[inline]
  fn next(&mut self) -> Option<Value> {
    self.iter.next()
  }
}

#[cfg(test)]
mod tests {
  #[test]
  fn test_get_primitive() {
    assert_eq!(vnull!().get(point![]), Some(vnull!()));
    assert_eq!(vnull!().get(point!["hello"]), None);
    assert_eq!(vnull!().get(point!["a", "b", "c", "d", "e"]), None);
    assert_eq!(vbool!(true).get(point![]), Some(vbool!(true)));
    assert_eq!(vbool!(true).get(point!["hello"]), None);
    assert_eq!(vi64!(36).get(point![]), Some(vi64!(36)));
    assert_eq!(vi64!(36).get(point!["hello"]), None);
    assert_eq!(vstring!("world").get(point![]), Some(vstring!("world")));
    assert_eq!(vstring!("world").get(point!["hello"]), None);
  }

  #[test]
  fn test_get_object() {
    let object = vobject!{
      "hello" => vbool!(true),
      "world" => vi64!(8),
      "5" => vnull!(),
      "moon" => vobject!{
        "hello" => vstring!("yoyo")
      }
    };
    assert_eq!(object.get(point![]), Some(object.clone()));
    assert_eq!(object.get(point!["hello"]), Some(vbool!(true)));
    assert_eq!(object.get(point!["5"]), Some(vnull!()));
    assert_eq!(object.get(point!["world", "hello"]), None);
    assert_eq!(object.get(point!["moon", "hello"]), Some(vstring!("yoyo")));
    assert_eq!(object.get(point!["moon", "nope"]), None);
  }

  #[test]
  fn test_get_array() {
    let array = varray![
      vbool!(false),
      vi64!(64),
      vobject!{
        "hello" => vbool!(true),
        "world" => vbool!(false),
        "moon" => vobject!{
          "goodbye" => vstring!("yoyo")
        }
      },
      varray![
        varray![
          vi64!(1),
          vi64!(2),
          vi64!(3)
        ],
        vi64!(4),
        vi64!(5)
      ]
    ];
    assert_eq!(array.get(point![]), Some(array.clone()));
    assert_eq!(array.get(point!["0"]), Some(vbool!(false)));
    assert_eq!(array.get(point!["1"]), Some(vi64!(64)));
    assert_eq!(array.get(point!["2", "hello"]), Some(vbool!(true)));
    assert_eq!(array.get(point!["2", "moon", "goodbye"]), Some(vstring!("yoyo")));
    assert_eq!(array.get(point!["length"]), None);
    assert_eq!(array.get(point!["3", "0", "1"]), Some(vi64!(2)));
  }

  #[test]
  fn test_to_json() {
    assert_eq!(&vnull!().to_json(), "null");
    assert_eq!(&vbool!(true).to_json(), "true");
    assert_eq!(&vbool!(false).to_json(), "false");
    assert_eq!(&vi64!(7).to_json(), "7");
    assert_eq!(&vf64!(6.667).to_json(), "6.667");
    assert_eq!(&vstring!("Hello,\n\"world\"!").to_json(), r#""Hello,\n\"world\"!""#);
    assert_eq!(&vobject! {
      "hello" => vstring!("world"),
      "foo" => vbool!(true),
      "goodbye" => vobject! {
        "moon" => vi64!(2)
      }
    }.to_json(), r#"{"hello":"world","foo":true,"goodbye":{"moon":2}}"#);
    assert_eq!(&varray![
      vstring!("world"),
      vf64!(3.333),
      vobject! {
        "hello" => vstring!("world")
      },
      vnull!(),
      vnull!(),
      varray![vi64!(1), vi64!(2), vi64!(3)],
      vnull!()
    ].to_json(), r#"["world",3.333,{"hello":"world"},null,null,[1,2,3],null]"#);
  }
}
<commit_msg>doc(value): better docs for key and pointer<commit_after>//! Types representing for data which will be retrieved from the driver.
//! Currently this data is expected to look like a JSON object but this may be
//! changed in the future. Driver authors must cast the data they retrieve from
//! the driver to these types.

use linear_map::LinearMap;

/// The type which represents the key for maps used throughout the Ardite
/// codebase.
///
/// Functions similarly to an object key in JavaScript.
pub type Key = String;

/// Represents a [JSON pointer][1] to a document property. Examples of a
/// pointer in this context include `/hello/world` or `/a/b/c/d`.
///
/// These pointers are represented as a list of keys.
///
/// [1]: https://duckduckgo.com/?q=json+pointer&atb=v1&ia=about
pub type Pointer = Vec<Key>;

/// Various value types. Based on types in the [JSON standard][1] (see section
/// 5).
///
/// [1]: http://ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
#[derive(PartialEq, Clone, Debug)]
pub enum Value {
  /// The abscense of any value.
  Null,
  /// True or false.
  Boolean(bool),
  /// An integer numeric value.
  I64(i64),
  /// A floating point numeric value.
  F64(f64),
  /// A list of characters.
  String(String),
  /// A map of key/value pairs. Backed by a linear map to maintain order and
  /// have high performance for small objects.
  Object(LinearMap<Key, Value>),
  /// A list of values. Just a value, but using *only* integer keys.
  Array(Vec<Value>)
}

impl Value {
  /// Gets a value at a specific point. Helpful for retrieving nested values.
  pub fn get(&self, mut pointer: Pointer) -> Option<Value> {
    match *self {
      Value::Object(ref map) => {
        if pointer.is_empty() {
          Some(self.clone())
        } else if let Some(value) = map.get(&pointer.remove(0)) {
          value.get(pointer)
        } else {
          None
        }
      },
      Value::Array(ref vec) => {
        if pointer.is_empty() {
          Some(self.clone())
        } else if let Some(value) = pointer.remove(0).parse::<usize>().ok().map_or(None, |i| vec.get(i)) {
          value.get(pointer)
        } else {
          None
        }
      },
      _ => if pointer.is_empty() { Some(self.clone()) } else { None }
    }
  }

  /// Converts a value into a JSON string for distribution.
  pub fn to_json(&self) -> String {
    match *self {
      Value::Null => "null".to_owned(),
      Value::Boolean(value) => if value { "true".to_owned() } else { "false".to_owned() },
      Value::I64(value) => value.to_string(),
      Value::F64(value) => value.to_string(),
      Value::String(ref value) => "\"".to_owned() + &escape_string_for_json(value) + "\"",
      Value::Object(ref map) => {
        let mut json = "{".to_owned();
        for (key, value) in map {
          json.push_str("\"");
          json.push_str(&escape_string_for_json(key));
          json.push_str("\":");
          json.push_str(&value.to_json());
          json.push_str(",");
        }
        // Remove the last comma.
        json.pop();
        json.push_str("}");
        json
      },
      Value::Array(ref vec) => {
        let mut json = "[".to_owned();
        for item in vec {
          json.push_str(&item.to_json());
          json.push_str(",");
        }
        // Remove the last comma.
        json.pop();
        json.push_str("]");
        json
      }
    }
  }
}

/// Takes a string and escapes it for use within a JSON encoded object. Read,
/// inside quotes.
fn escape_string_for_json(string: &str) -> String {
  string.replace("\"", "\\\"").replace("\n", "\\n")
}

/// An iterator of values. Used by drivers to convert their own iterator
/// implementations into a single type.
pub struct ValueIter<'a> {
  iter: Box<Iterator<Item=Value> + 'a>
}

impl<'a> ValueIter<'a> {
  /// Create a new value iterator.
  pub fn new<I>(iter: I) -> Self where I: Iterator<Item=Value> + 'a {
    ValueIter {
      iter: Box::new(iter)
    }
  }
}

impl<'a> Iterator for ValueIter<'a> {
  type Item = Value;

  #[inline]
  fn next(&mut self) -> Option<Value> {
    self.iter.next()
  }
}

#[cfg(test)]
mod tests {
  #[test]
  fn test_get_primitive() {
    assert_eq!(vnull!().get(point![]), Some(vnull!()));
    assert_eq!(vnull!().get(point!["hello"]), None);
    assert_eq!(vnull!().get(point!["a", "b", "c", "d", "e"]), None);
    assert_eq!(vbool!(true).get(point![]), Some(vbool!(true)));
    assert_eq!(vbool!(true).get(point!["hello"]), None);
    assert_eq!(vi64!(36).get(point![]), Some(vi64!(36)));
    assert_eq!(vi64!(36).get(point!["hello"]), None);
    assert_eq!(vstring!("world").get(point![]), Some(vstring!("world")));
    assert_eq!(vstring!("world").get(point!["hello"]), None);
  }

  #[test]
  fn test_get_object() {
    let object = vobject!{
      "hello" => vbool!(true),
      "world" => vi64!(8),
      "5" => vnull!(),
      "moon" => vobject!{
        "hello" => vstring!("yoyo")
      }
    };
    assert_eq!(object.get(point![]), Some(object.clone()));
    assert_eq!(object.get(point!["hello"]), Some(vbool!(true)));
    assert_eq!(object.get(point!["5"]), Some(vnull!()));
    assert_eq!(object.get(point!["world", "hello"]), None);
    assert_eq!(object.get(point!["moon", "hello"]), Some(vstring!("yoyo")));
    assert_eq!(object.get(point!["moon", "nope"]), None);
  }

  #[test]
  fn test_get_array() {
    let array = varray![
      vbool!(false),
      vi64!(64),
      vobject!{
        "hello" => vbool!(true),
        "world" => vbool!(false),
        "moon" => vobject!{
          "goodbye" => vstring!("yoyo")
        }
      },
      varray![
        varray![
          vi64!(1),
          vi64!(2),
          vi64!(3)
        ],
        vi64!(4),
        vi64!(5)
      ]
    ];
    assert_eq!(array.get(point![]), Some(array.clone()));
    assert_eq!(array.get(point!["0"]), Some(vbool!(false)));
    assert_eq!(array.get(point!["1"]), Some(vi64!(64)));
    assert_eq!(array.get(point!["2", "hello"]), Some(vbool!(true)));
    assert_eq!(array.get(point!["2", "moon", "goodbye"]), Some(vstring!("yoyo")));
    assert_eq!(array.get(point!["length"]), None);
    assert_eq!(array.get(point!["3", "0", "1"]), Some(vi64!(2)));
  }

  #[test]
  fn test_to_json() {
    assert_eq!(&vnull!().to_json(), "null");
    assert_eq!(&vbool!(true).to_json(), "true");
    assert_eq!(&vbool!(false).to_json(), "false");
    assert_eq!(&vi64!(7).to_json(), "7");
    assert_eq!(&vf64!(6.667).to_json(), "6.667");
    assert_eq!(&vstring!("Hello,\n\"world\"!").to_json(), r#""Hello,\n\"world\"!""#);
    assert_eq!(&vobject! {
      "hello" => vstring!("world"),
      "foo" => vbool!(true),
      "goodbye" => vobject! {
        "moon" => vi64!(2)
      }
    }.to_json(), r#"{"hello":"world","foo":true,"goodbye":{"moon":2}}"#);
    assert_eq!(&varray![
      vstring!("world"),
      vf64!(3.333),
      vobject! {
        "hello" => vstring!("world")
      },
      vnull!(),
      vnull!(),
      varray![vi64!(1), vi64!(2), vi64!(3)],
      vnull!()
    ].to_json(), r#"["world",3.333,{"hello":"world"},null,null,[1,2,3],null]"#);
  }
}
<|endoftext|>