<commit_before>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use std::thread::{self,Thread,Builder};
use std::sync::mpsc::TryRecvError;
use std::net::{SocketAddr,Shutdown};
use std::rc::Rc;
use std::cell::RefCell;
use mio::net::*;
use mio::*;
use mio::unix::UnixReady;
use std::collections::{HashSet,HashMap,VecDeque};
use std::io::{self,Read,ErrorKind};
use nom::HexDisplay;
use std::error::Error;
use slab::Slab;
use pool::Pool;
use std::io::Write;
use std::str::FromStr;
use std::marker::PhantomData;
use std::fmt::Debug;
use time::precise_time_ns;
use std::time::Duration;
use rand::random;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::messages::{self,TcpFront,Order,Instance,MessageId,OrderMessageAnswer,OrderMessageAnswerData,OrderMessageStatus,OrderMessage,Topic,Query,QueryAnswer};

use network::buffer_queue::BufferQueue;
use network::{ClientResult,ConnectionError,
  SocketType,Protocol,RequiredEvents};
use network::{http,tls,tcp};
use network::metrics::METRICS;
use network::session::{BackToken,FrontToken,ListenToken,ProxyClient,ProxyConfiguration,Readiness,Session};

const SERVER: Token = Token(0);
const DEFAULT_FRONT_TIMEOUT: u64 = 50000;
const DEFAULT_BACK_TIMEOUT:  u64 = 50000;

pub type ProxyChannel = Channel<OrderMessageAnswer,OrderMessage>;

#[derive(Debug,Clone,PartialEq)]
enum ProxyType {
  HTTP,
  HTTPS,
  TCP,
}

pub struct Server {
  pub poll:        Poll,
  shutting_down:   Option<MessageId>,
  accept_ready:    HashSet<ListenToken>,
  can_accept:      bool,
  channel:         ProxyChannel,
  queue:           VecDeque<OrderMessageAnswer>,
  http:            Option<Session<http::ServerConfiguration, http::Client>>,
  https:           Option<Session<tls::ServerConfiguration, tls::TlsClient>>,
  tcp:             Option<Session<tcp::ServerConfiguration, tcp::Client>>,
  config_state:    ConfigState,
}

impl Server {
  pub fn new_from_config(channel: ProxyChannel, config: Config, config_state: ConfigState) -> Self {
    let mut event_loop  = Poll::new().expect("could not create event loop");
    let pool = Rc::new(RefCell::new(
      Pool::with_capacity(2*config.max_buffers, 0, || BufferQueue::with_capacity(config.buffer_size))
    ));

    let max_connections = config.max_connections;
    let max_buffers     = config.max_buffers;
    let http_session = config.http.and_then(|conf| conf.to_http()).and_then(|http_conf| {
      let max_listeners = 1;
      http::ServerConfiguration::new(http_conf, &mut event_loop, 1 + max_listeners, pool.clone()).map(|configuration| {
        Session::new(1, max_connections, 0, configuration, &mut event_loop)
      }).ok()
    });

    let https_session = config.https.and_then(|conf| conf.to_tls()).and_then(|https_conf| {
      let max_listeners   = 1;
      tls::ServerConfiguration::new(https_conf, 6148914691236517205, &mut event_loop, 1 + max_listeners + 6148914691236517205, pool.clone()).map(|configuration| {
        Session::new(max_listeners, max_connections, 6148914691236517205, configuration, &mut event_loop)
      }).ok()
    });

    let tcp_session = config.tcp.map(|conf| {
      let configuration = tcp::ServerConfiguration::new(conf.max_listeners, 12297829382473034410, pool.clone());
      Session::new(conf.max_listeners, max_buffers, 12297829382473034410, configuration, &mut event_loop)
    });

    Server::new(event_loop, channel, http_session, https_session, tcp_session, Some(config_state))
  }

  pub fn new(poll: Poll, channel: ProxyChannel,
    http:  Option<Session<http::ServerConfiguration, http::Client>>,
    https: Option<Session<tls::ServerConfiguration, tls::TlsClient>>,
    tcp:  Option<Session<tcp::ServerConfiguration, tcp::Client>>,
    config_state: Option<ConfigState>) -> Self {

    poll.register(
      &channel,
      Token(0),
      Ready::readable() | Ready::writable() | Ready::from(UnixReady::hup() | UnixReady::error()),
      PollOpt::edge()
    ).expect("should register the channel");

    METRICS.with(|metrics| {
      if let Some(sock) = (*metrics.borrow()).socket() {
        poll.register(sock, Token(1), Ready::writable(), PollOpt::edge()).expect("should register the metrics socket");
      } else {
        error!("could not register metrics socket");
      }
    });

    let mut server = Server {
      poll:            poll,
      shutting_down:   None,
      accept_ready:    HashSet::new(),
      can_accept:      true,
      channel:         channel,
      queue:           VecDeque::new(),
      http:            http,
      https:           https,
      tcp:             tcp,
      config_state:    ConfigState::new(),
    };

    // initialize the worker with the state we got from a file
    if let Some(state) = config_state {
      let mut counter = 0usize;

      for order in state.generate_orders() {
        let id = format!("INIT-{}", counter);
        let message = OrderMessage {
          id:    id,
          order: order,
        };

        trace!("generating initial config order: {:#?}", message);
        server.notify_sessions(message);

        counter += 1;
      }
      // do not send back answers to the initialization messages
      server.queue.clear();
    }

    server
  }
}

//type Timeout = usize;

impl Server {
  pub fn run(&mut self) {
    //FIXME: make those parameters configurable?
    let mut events = Events::with_capacity(1024);
    let poll_timeout = Some(Duration::from_millis(1000));
    loop {
      self.poll.poll(&mut events, poll_timeout).expect("should be able to poll for events");

      for event in events.iter() {
        if event.token() == Token(0) {
          let kind = event.readiness();
          if UnixReady::from(kind).is_error() {
            error!("error reading from command channel");
            continue;
          }
          if UnixReady::from(kind).is_hup() {
            error!("command channel was closed");
            continue;
          }
          self.channel.handle_events(kind);

          // loop here because iterations has borrow issues
          loop {
            if !self.queue.is_empty() {
              self.channel.interest.insert(Ready::writable());
            }

            //trace!("WORKER[{}] channel readiness={:?}, interest={:?}, queue={} elements",
            //  line!(), self.channel.readiness, self.channel.interest, self.queue.len());
            if self.channel.readiness() == Ready::empty() {
              break;
            }

            if self.channel.readiness().is_readable() {
              self.channel.readable();

              loop {
                let msg = self.channel.read_message();

                // if the message was too large, we grow the buffer and retry to read if possible
                if msg.is_none() {
                  if (self.channel.interest & self.channel.readiness).is_readable() {
                    self.channel.readable();
                    continue;
                  } else {
                    break;
                  }
                }

                let msg = msg.expect("the message should be valid");
                if let Order::HardStop = msg.order {
                  let id_msg = msg.id.clone();
                  self.notify(msg);
                  self.channel.write_message(&OrderMessageAnswer{ id: id_msg, status: OrderMessageStatus::Ok, data: None});
                  self.channel.run();
                  return;
                } else if let Order::SoftStop = msg.order {
                  self.shutting_down = Some(msg.id.clone());
                  self.notify(msg);
                } else {
                  self.notify(msg);
                }

              }
            }

            if !self.queue.is_empty() {
              self.channel.interest.insert(Ready::writable());
            }
            if self.channel.readiness.is_writable() {

              loop {

                if let Some(msg) = self.queue.pop_front() {
                  if !self.channel.write_message(&msg) {
                    self.queue.push_front(msg);
                  }
                }

                if self.channel.back_buf.available_data() > 0 {
                  self.channel.writable();
                }

                if !self.channel.readiness.is_writable() {
                  break;
                }

                if self.channel.back_buf.available_data() == 0 && self.queue.len() == 0 {
                  break;
                }
              }
            }
          }

        } else if event.token() == Token(1) {
          METRICS.with(|metrics| {
            (*metrics.borrow_mut()).writable();
          });
        } else {
          //self.ready(event.token(), event.readiness());
          match proxy_type(event.token().0) {
            ProxyType::HTTP  => if let Some(mut http) = self.http.take() {
              http.ready(&mut self.poll, event.token(), event.readiness());
              self.http = Some(http);
            },
            ProxyType::HTTPS => if let Some(mut https) = self.https.take() {
              https.ready(&mut self.poll, event.token(), event.readiness());
              self.https = Some(https);
            },
            ProxyType::TCP   => if let Some(mut tcp) = self.tcp.take() {
              tcp.ready(&mut self.poll, event.token(), event.readiness());
              self.tcp = Some(tcp);
            },
          };
        }
      }

      if let Some(mut http) = self.http.take() {
        http.handle_remaining_readiness(&mut self.poll);
        self.http = Some(http);
      }
      if let Some(mut https) = self.https.take() {
        https.handle_remaining_readiness(&mut self.poll);
        self.https = Some(https);
      }
      if let Some(mut tcp) = self.tcp.take() {
        tcp.handle_remaining_readiness(&mut self.poll);
        self.tcp = Some(tcp);
      }

      METRICS.with(|metrics| {
        (*metrics.borrow_mut()).send_data();
      });

      if self.shutting_down.is_some() {
        info!("last client stopped, shutting down!");
        self.channel.write_message(&OrderMessageAnswer{ id: self.shutting_down.take().expect("should have shut down correctly"), status: OrderMessageStatus::Ok, data: None});
        self.channel.run();
        return;
      }
    }
  }

  fn notify(&mut self, message: OrderMessage) {
    if let Order::Metrics = message.order {
      let q = &mut self.queue;
      //let id = message.id.clone();
      let msg = METRICS.with(|metrics| {
        q.push_back(OrderMessageAnswer {
          id:     message.id.clone(),
          status: OrderMessageStatus::Ok,
          data:   Some(OrderMessageAnswerData::Metrics(
            (*metrics.borrow_mut()).dump_metrics_data()
          ))
        });
      });
      return;
    }

    if let Order::Query(ref query) = message.order {
      match query {
        &Query::Applications => {
          self.queue.push_back(OrderMessageAnswer {
            id:     message.id.clone(),
            status: OrderMessageStatus::Ok,
            data:   Some(OrderMessageAnswerData::Query(
              QueryAnswer::Applications(self.config_state.hash_state())
            ))
          });
        },
        &Query::Application(ref app_id) => {
          self.queue.push_back(OrderMessageAnswer {
            id:     message.id.clone(),
            status: OrderMessageStatus::Ok,
            data:   Some(OrderMessageAnswerData::Query(
              QueryAnswer::Application(self.config_state.application_state(app_id))
            ))
          });
        }
      }
      return
    }

    self.notify_sessions(message);
  }

  pub fn notify_sessions(&mut self, message: OrderMessage) {
    self.config_state.handle_order(&message.order);

    let topics = message.order.get_topics();

    if topics.contains(&Topic::HttpProxyConfig) {
      if let Some(mut http) = self.http.take() {
        self.queue.push_back(http.configuration().notify(&mut self.poll, message.clone()));
        self.http = Some(http);
      }
    }
    if topics.contains(&Topic::HttpsProxyConfig) {
      if let Some(mut https) = self.https.take() {
        self.queue.push_back(https.configuration().notify(&mut self.poll, message.clone()));
        self.https = Some(https);
      }
    }
    if topics.contains(&Topic::TcpProxyConfig) {
      if let Some(mut tcp) = self.tcp.take() {
        self.queue.push_back(tcp.configuration().notify(&mut self.poll, message));
        self.tcp = Some(tcp);
      }
    }
  }
}

fn proxy_type(token: usize) -> ProxyType {
  if token < 6148914691236517205 {
    ProxyType::HTTP
  } else if token < 12297829382473034410 {
    ProxyType::HTTPS
  } else {
    ProxyType::TCP
  }
}
<commit_msg>do not close the worker until the last message was sent<commit_after>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use std::thread::{self,Thread,Builder};
use std::sync::mpsc::TryRecvError;
use std::net::{SocketAddr,Shutdown};
use std::rc::Rc;
use std::cell::RefCell;
use mio::net::*;
use mio::*;
use mio::unix::UnixReady;
use std::collections::{HashSet,HashMap,VecDeque};
use std::io::{self,Read,ErrorKind};
use nom::HexDisplay;
use std::error::Error;
use slab::Slab;
use pool::Pool;
use std::io::Write;
use std::str::FromStr;
use std::marker::PhantomData;
use std::fmt::Debug;
use time::precise_time_ns;
use std::time::Duration;
use rand::random;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::messages::{self,TcpFront,Order,Instance,MessageId,OrderMessageAnswer,OrderMessageAnswerData,OrderMessageStatus,OrderMessage,Topic,Query,QueryAnswer};

use network::buffer_queue::BufferQueue;
use network::{ClientResult,ConnectionError,
  SocketType,Protocol,RequiredEvents};
use network::{http,tls,tcp};
use network::metrics::METRICS;
use network::session::{BackToken,FrontToken,ListenToken,ProxyClient,ProxyConfiguration,Readiness,Session};

const SERVER: Token = Token(0);
const DEFAULT_FRONT_TIMEOUT: u64 = 50000;
const DEFAULT_BACK_TIMEOUT:  u64 = 50000;

pub type ProxyChannel = Channel<OrderMessageAnswer,OrderMessage>;

#[derive(Debug,Clone,PartialEq)]
enum ProxyType {
  HTTP,
  HTTPS,
  TCP,
}

pub struct Server {
  pub poll:        Poll,
  shutting_down:   Option<MessageId>,
  accept_ready:    HashSet<ListenToken>,
  can_accept:      bool,
  channel:         ProxyChannel,
  queue:           VecDeque<OrderMessageAnswer>,
  http:            Option<Session<http::ServerConfiguration, http::Client>>,
  https:           Option<Session<tls::ServerConfiguration, tls::TlsClient>>,
  tcp:             Option<Session<tcp::ServerConfiguration, tcp::Client>>,
  config_state:    ConfigState,
}

impl Server {
  pub fn new_from_config(channel: ProxyChannel, config: Config, config_state: ConfigState) -> Self {
    let mut event_loop  = Poll::new().expect("could not create event loop");
    let pool = Rc::new(RefCell::new(
      Pool::with_capacity(2*config.max_buffers, 0, || BufferQueue::with_capacity(config.buffer_size))
    ));

    let max_connections = config.max_connections;
    let max_buffers     = config.max_buffers;
    let http_session = config.http.and_then(|conf| conf.to_http()).and_then(|http_conf| {
      let max_listeners = 1;
      http::ServerConfiguration::new(http_conf, &mut event_loop, 1 + max_listeners, pool.clone()).map(|configuration| {
        Session::new(1, max_connections, 0, configuration, &mut event_loop)
      }).ok()
    });

    let https_session = config.https.and_then(|conf| conf.to_tls()).and_then(|https_conf| {
      let max_listeners   = 1;
      tls::ServerConfiguration::new(https_conf, 6148914691236517205, &mut event_loop, 1 + max_listeners + 6148914691236517205, pool.clone()).map(|configuration| {
        Session::new(max_listeners, max_connections, 6148914691236517205, configuration, &mut event_loop)
      }).ok()
    });

    let tcp_session = config.tcp.map(|conf| {
      let configuration = tcp::ServerConfiguration::new(conf.max_listeners, 12297829382473034410, pool.clone());
      Session::new(conf.max_listeners, max_buffers, 12297829382473034410, configuration, &mut event_loop)
    });

    Server::new(event_loop, channel, http_session, https_session, tcp_session, Some(config_state))
  }

  pub fn new(poll: Poll, channel: ProxyChannel,
    http:  Option<Session<http::ServerConfiguration, http::Client>>,
    https: Option<Session<tls::ServerConfiguration, tls::TlsClient>>,
    tcp:  Option<Session<tcp::ServerConfiguration, tcp::Client>>,
    config_state: Option<ConfigState>) -> Self {

    poll.register(
      &channel,
      Token(0),
      Ready::readable() | Ready::writable() | Ready::from(UnixReady::hup() | UnixReady::error()),
      PollOpt::edge()
    ).expect("should register the channel");

    METRICS.with(|metrics| {
      if let Some(sock) = (*metrics.borrow()).socket() {
        poll.register(sock, Token(1), Ready::writable(), PollOpt::edge()).expect("should register the metrics socket");
      } else {
        error!("could not register metrics socket");
      }
    });

    let mut server = Server {
      poll:            poll,
      shutting_down:   None,
      accept_ready:    HashSet::new(),
      can_accept:      true,
      channel:         channel,
      queue:           VecDeque::new(),
      http:            http,
      https:           https,
      tcp:             tcp,
      config_state:    ConfigState::new(),
    };

    // initialize the worker with the state we got from a file
    if let Some(state) = config_state {
      let mut counter = 0usize;

      for order in state.generate_orders() {
        let id = format!("INIT-{}", counter);
        let message = OrderMessage {
          id:    id,
          order: order,
        };

        trace!("generating initial config order: {:#?}", message);
        server.notify_sessions(message);

        counter += 1;
      }
      // do not send back answers to the initialization messages
      server.queue.clear();
    }

    server
  }
}

//type Timeout = usize;

impl Server {
  pub fn run(&mut self) {
    //FIXME: make those parameters configurable?
    let mut events = Events::with_capacity(1024);
    let poll_timeout = Some(Duration::from_millis(1000));
    loop {
      self.poll.poll(&mut events, poll_timeout).expect("should be able to poll for events");

      for event in events.iter() {
        if event.token() == Token(0) {
          let kind = event.readiness();
          if UnixReady::from(kind).is_error() {
            error!("error reading from command channel");
            continue;
          }
          if UnixReady::from(kind).is_hup() {
            error!("command channel was closed");
            continue;
          }
          self.channel.handle_events(kind);

          // loop here because iterations has borrow issues
          loop {
            if !self.queue.is_empty() {
              self.channel.interest.insert(Ready::writable());
            }

            //trace!("WORKER[{}] channel readiness={:?}, interest={:?}, queue={} elements",
            //  line!(), self.channel.readiness, self.channel.interest, self.queue.len());
            if self.channel.readiness() == Ready::empty() {
              break;
            }

            if self.channel.readiness().is_readable() {
              self.channel.readable();

              loop {
                let msg = self.channel.read_message();

                // if the message was too large, we grow the buffer and retry to read if possible
                if msg.is_none() {
                  if (self.channel.interest & self.channel.readiness).is_readable() {
                    self.channel.readable();
                    continue;
                  } else {
                    break;
                  }
                }

                let msg = msg.expect("the message should be valid");
                if let Order::HardStop = msg.order {
                  let id_msg = msg.id.clone();
                  self.notify(msg);
                  self.channel.write_message(&OrderMessageAnswer{ id: id_msg, status: OrderMessageStatus::Ok, data: None});
                  self.channel.run();
                  return;
                } else if let Order::SoftStop = msg.order {
                  self.shutting_down = Some(msg.id.clone());
                  self.notify(msg);
                } else {
                  self.notify(msg);
                }

              }
            }

            if !self.queue.is_empty() {
              self.channel.interest.insert(Ready::writable());
            }
            if self.channel.readiness.is_writable() {

              loop {

                if let Some(msg) = self.queue.pop_front() {
                  if !self.channel.write_message(&msg) {
                    self.queue.push_front(msg);
                  }
                }

                if self.channel.back_buf.available_data() > 0 {
                  self.channel.writable();
                }

                if !self.channel.readiness.is_writable() {
                  break;
                }

                if self.channel.back_buf.available_data() == 0 && self.queue.len() == 0 {
                  break;
                }
              }
            }
          }

        } else if event.token() == Token(1) {
          METRICS.with(|metrics| {
            (*metrics.borrow_mut()).writable();
          });
        } else {
          //self.ready(event.token(), event.readiness());
          match proxy_type(event.token().0) {
            ProxyType::HTTP  => if let Some(mut http) = self.http.take() {
              http.ready(&mut self.poll, event.token(), event.readiness());
              self.http = Some(http);
            },
            ProxyType::HTTPS => if let Some(mut https) = self.https.take() {
              https.ready(&mut self.poll, event.token(), event.readiness());
              self.https = Some(https);
            },
            ProxyType::TCP   => if let Some(mut tcp) = self.tcp.take() {
              tcp.ready(&mut self.poll, event.token(), event.readiness());
              self.tcp = Some(tcp);
            },
          };
        }
      }

      if let Some(mut http) = self.http.take() {
        http.handle_remaining_readiness(&mut self.poll);
        self.http = Some(http);
      }
      if let Some(mut https) = self.https.take() {
        https.handle_remaining_readiness(&mut self.poll);
        self.https = Some(https);
      }
      if let Some(mut tcp) = self.tcp.take() {
        tcp.handle_remaining_readiness(&mut self.poll);
        self.tcp = Some(tcp);
      }

      METRICS.with(|metrics| {
        (*metrics.borrow_mut()).send_data();
      });

      if self.shutting_down.is_some() {
        info!("last client stopped, shutting down!");
        self.channel.run();
        self.channel.set_blocking(true);
        self.channel.write_message(&OrderMessageAnswer{ id: self.shutting_down.take().expect("should have shut down correctly"), status: OrderMessageStatus::Ok, data: None});
        return;
      }
    }
  }

  fn notify(&mut self, message: OrderMessage) {
    if let Order::Metrics = message.order {
      let q = &mut self.queue;
      //let id = message.id.clone();
      let msg = METRICS.with(|metrics| {
        q.push_back(OrderMessageAnswer {
          id:     message.id.clone(),
          status: OrderMessageStatus::Ok,
          data:   Some(OrderMessageAnswerData::Metrics(
            (*metrics.borrow_mut()).dump_metrics_data()
          ))
        });
      });
      return;
    }

    if let Order::Query(ref query) = message.order {
      match query {
        &Query::Applications => {
          self.queue.push_back(OrderMessageAnswer {
            id:     message.id.clone(),
            status: OrderMessageStatus::Ok,
            data:   Some(OrderMessageAnswerData::Query(
              QueryAnswer::Applications(self.config_state.hash_state())
            ))
          });
        },
        &Query::Application(ref app_id) => {
          self.queue.push_back(OrderMessageAnswer {
            id:     message.id.clone(),
            status: OrderMessageStatus::Ok,
            data:   Some(OrderMessageAnswerData::Query(
              QueryAnswer::Application(self.config_state.application_state(app_id))
            ))
          });
        }
      }
      return
    }

    self.notify_sessions(message);
  }

  pub fn notify_sessions(&mut self, message: OrderMessage) {
    self.config_state.handle_order(&message.order);

    let topics = message.order.get_topics();

    if topics.contains(&Topic::HttpProxyConfig) {
      if let Some(mut http) = self.http.take() {
        self.queue.push_back(http.configuration().notify(&mut self.poll, message.clone()));
        self.http = Some(http);
      }
    }
    if topics.contains(&Topic::HttpsProxyConfig) {
      if let Some(mut https) = self.https.take() {
        self.queue.push_back(https.configuration().notify(&mut self.poll, message.clone()));
        self.https = Some(https);
      }
    }
    if topics.contains(&Topic::TcpProxyConfig) {
      if let Some(mut tcp) = self.tcp.take() {
        self.queue.push_back(tcp.configuration().notify(&mut self.poll, message));
        self.tcp = Some(tcp);
      }
    }
  }
}

fn proxy_type(token: usize) -> ProxyType {
  if token < 6148914691236517205 {
    ProxyType::HTTP
  } else if token < 12297829382473034410 {
    ProxyType::HTTPS
  } else {
    ProxyType::TCP
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;

use glium::{Surface, BlitTarget, Rect};

mod support;

#[test]
fn blit_texture_to_window() {
    // ignoring test on travis
    // TODO: find out why they are failing
    if ::std::env::var("TRAVIS").is_ok() {
        return;
    }

    let display = support::build_display();

    let src_rect = Rect {
        left: 0,
        bottom: 0,
        width: 2,
        height: 2,
    };

    let dest_rect = BlitTarget {
        left: 1,
        bottom: 1,
        width: 2,
        height: 2,
    };

    let texture = support::build_unicolor_texture2d(&display, 0.0, 1.0, 0.0);

    let target = support::build_renderable_texture(&display);
    target.as_surface().clear_color(0.0, 0.0, 0.0, 0.0);

    texture.as_surface().blit_color(&src_rect, &target.as_surface(), &dest_rect,
                                    glium::uniforms::MagnifySamplerFilter::Nearest);

    let data: Vec<Vec<(u8, u8, u8, u8)>> = target.read();

    assert_eq!(data[1][1], (0, 255, 0, 255));
    assert_eq!(data[1][2], (0, 255, 0, 255));
    assert_eq!(data[2][1], (0, 255, 0, 255));
    assert_eq!(data[2][2], (0, 255, 0, 255));

    assert_eq!(data[0][0], (0, 0, 0, 0));

    assert_eq!(data[0][1], (0, 0, 0, 0));
    assert_eq!(data[0][2], (0, 0, 0, 0));

    assert_eq!(data[1][0], (0, 0, 0, 0));
    assert_eq!(data[2][0], (0, 0, 0, 0));

    assert_eq!(data[3][1], (0, 0, 0, 0));
    assert_eq!(data[3][2], (0, 0, 0, 0));

    assert_eq!(data[2][3], (0, 0, 0, 0));
    assert_eq!(data[1][3], (0, 0, 0, 0));

    assert_eq!(data[3][3], (0, 0, 0, 0));

    display.assert_no_error(None);
}
<commit_msg>Restore the blit test on travis<commit_after>#[macro_use]
extern crate glium;

use glium::{Surface, BlitTarget, Rect};

mod support;

#[test]
fn blit_texture_to_window() {
    let display = support::build_display();

    let src_rect = Rect {
        left: 0,
        bottom: 0,
        width: 2,
        height: 2,
    };

    let dest_rect = BlitTarget {
        left: 1,
        bottom: 1,
        width: 2,
        height: 2,
    };

    let texture = support::build_unicolor_texture2d(&display, 0.0, 1.0, 0.0);

    let target = support::build_renderable_texture(&display);
    target.as_surface().clear_color(0.0, 0.0, 0.0, 0.0);

    texture.as_surface().blit_color(&src_rect, &target.as_surface(), &dest_rect,
                                    glium::uniforms::MagnifySamplerFilter::Nearest);

    let data: Vec<Vec<(u8, u8, u8, u8)>> = target.read();

    assert_eq!(data[1][1], (0, 255, 0, 255));
    assert_eq!(data[1][2], (0, 255, 0, 255));
    assert_eq!(data[2][1], (0, 255, 0, 255));
    assert_eq!(data[2][2], (0, 255, 0, 255));

    assert_eq!(data[0][0], (0, 0, 0, 0));

    assert_eq!(data[0][1], (0, 0, 0, 0));
    assert_eq!(data[0][2], (0, 0, 0, 0));

    assert_eq!(data[1][0], (0, 0, 0, 0));
    assert_eq!(data[2][0], (0, 0, 0, 0));

    assert_eq!(data[3][1], (0, 0, 0, 0));
    assert_eq!(data[3][2], (0, 0, 0, 0));

    assert_eq!(data[2][3], (0, 0, 0, 0));
    assert_eq!(data[1][3], (0, 0, 0, 0));

    assert_eq!(data[3][3], (0, 0, 0, 0));

    display.assert_no_error(None);
}
<|endoftext|>


<commit_before>#![cfg(feature = "full")]

#[macro_use]
extern crate quote;
extern crate syn;
extern crate synom;
extern crate syntex_pos;
extern crate syntex_syntax;
extern crate walkdir;

use syntex_syntax::ast;
use syntex_syntax::parse::{self, ParseSess, PResult};
use syntex_syntax::codemap::FilePathMapping;
use walkdir::{WalkDir, WalkDirIterator};

use std::fs::File;
use std::io::Read;
use std::panic;
use std::time::Instant;

#[allow(dead_code)]
#[macro_use]
mod common;

#[test]
fn test_round_trip() {
    common::check_min_stack();
    common::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all round_trip tests");
    }

    let mut failed = 0;

    let walk = WalkDir::new("tests/rust").sort_by(|a, b| a.cmp(b));
    for entry in walk.into_iter().filter_entry(common::base_dir_filter) {
        let entry = entry.unwrap();

        let path = entry.path();
        if path.is_dir() {
            continue;
        }
        errorf!("=== {}: ", path.display());

        let mut file = File::open(path).unwrap();
        let mut content = String::new();
        file.read_to_string(&mut content).unwrap();

        let start = Instant::now();
        let (krate, elapsed) = match syn::parse_file(&content) {
            Ok(krate) => (krate, start.elapsed()),
            Err(msg) => {
                errorf!("syn failed to parse\n{:?}\n", msg);
                failed += 1;
                if failed >= abort_after {
                    panic!("Aborting Immediately due to ABORT_AFTER_FAILURE");
                }
                continue;
            }
        };
        let back = quote!(#krate).to_string();

        let equal = panic::catch_unwind(|| {
            let sess = ParseSess::new(FilePathMapping::empty());
            let before = match syntex_parse(content, &sess) {
                Ok(before) => before,
                Err(mut diagnostic) => {
                    diagnostic.cancel();
                    if diagnostic.message().starts_with("file not found for module") {
                        errorf!("ignore\n");
                    } else {
                        errorf!("ignore - syntex failed to parse original content: {}\n", diagnostic.message());
                    }
                    return true;
                }
            };
            let after = match syntex_parse(back, &sess) {
                Ok(after) => after,
                Err(mut diagnostic) => {
                    errorf!("syntex failed to parse");
                    diagnostic.emit();
                    return false;
                }
            };

            if before == after {
                errorf!("pass in {}ms\n",
                        elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000);
                true
            } else {
                errorf!("FAIL\nbefore: {}\nafter: {}\n",
                        format!("{:?}", before).replace("\n", ""),
                        format!("{:?}", after).replace("\n", ""));
                false
            }
        });
        match equal {
            Err(_) => errorf!("ignoring syntex panic\n"),
            Ok(true) => {}
            Ok(false) => {
                failed += 1;
                if failed >= abort_after {
                    panic!("Aborting Immediately due to ABORT_AFTER_FAILURE");
                }
            },
        }
    }

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn syntex_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
    let name = "test_round_trip".to_string();
    parse::parse_crate_from_source_str(name, content, sess)
        .map(common::respan::respan_crate)
}
<commit_msg>Remove unused crates<commit_after>#![cfg(feature = "full")]

#[macro_use]
extern crate quote;
extern crate syn;
extern crate syntex_syntax;
extern crate walkdir;

use syntex_syntax::ast;
use syntex_syntax::parse::{self, ParseSess, PResult};
use syntex_syntax::codemap::FilePathMapping;
use walkdir::{WalkDir, WalkDirIterator};

use std::fs::File;
use std::io::Read;
use std::panic;
use std::time::Instant;

#[allow(dead_code)]
#[macro_use]
mod common;

#[test]
fn test_round_trip() {
    common::check_min_stack();
    common::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all round_trip tests");
    }

    let mut failed = 0;

    let walk = WalkDir::new("tests/rust").sort_by(|a, b| a.cmp(b));
    for entry in walk.into_iter().filter_entry(common::base_dir_filter) {
        let entry = entry.unwrap();

        let path = entry.path();
        if path.is_dir() {
            continue;
        }
        errorf!("=== {}: ", path.display());

        let mut file = File::open(path).unwrap();
        let mut content = String::new();
        file.read_to_string(&mut content).unwrap();

        let start = Instant::now();
        let (krate, elapsed) = match syn::parse_file(&content) {
            Ok(krate) => (krate, start.elapsed()),
            Err(msg) => {
                errorf!("syn failed to parse\n{:?}\n", msg);
                failed += 1;
                if failed >= abort_after {
                    panic!("Aborting Immediately due to ABORT_AFTER_FAILURE");
                }
                continue;
            }
        };
        let back = quote!(#krate).to_string();

        let equal = panic::catch_unwind(|| {
            let sess = ParseSess::new(FilePathMapping::empty());
            let before = match syntex_parse(content, &sess) {
                Ok(before) => before,
                Err(mut diagnostic) => {
                    diagnostic.cancel();
                    if diagnostic.message().starts_with("file not found for module") {
                        errorf!("ignore\n");
                    } else {
                        errorf!("ignore - syntex failed to parse original content: {}\n", diagnostic.message());
                    }
                    return true;
                }
            };
            let after = match syntex_parse(back, &sess) {
                Ok(after) => after,
                Err(mut diagnostic) => {
                    errorf!("syntex failed to parse");
                    diagnostic.emit();
                    return false;
                }
            };

            if before == after {
                errorf!("pass in {}ms\n",
                        elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000);
                true
            } else {
                errorf!("FAIL\nbefore: {}\nafter: {}\n",
                        format!("{:?}", before).replace("\n", ""),
                        format!("{:?}", after).replace("\n", ""));
                false
            }
        });
        match equal {
            Err(_) => errorf!("ignoring syntex panic\n"),
            Ok(true) => {}
            Ok(false) => {
                failed += 1;
                if failed >= abort_after {
                    panic!("Aborting Immediately due to ABORT_AFTER_FAILURE");
                }
            },
        }
    }

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn syntex_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
    let name = "test_round_trip".to_string();
    parse::parse_crate_from_source_str(name, content, sess)
        .map(common::respan::respan_crate)
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#[allow(unused_variables)]
pub mod storeid {
    use std::path::PathBuf;

    use ruru::{Class, Object, AnyObject, Boolean, RString, NilClass};

    use libimagstore::storeid::StoreId;

    wrappable_struct!(StoreId, StoreIdWrapper, STOREID_WRAPPER);
    class!(RStoreId);

    methods!(
        RStoreId,
        itself,

        fn r_storeid_new(base: RString, id: RString) -> AnyObject {
            let base = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(base) => base,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(Some(base), id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_new_baseless(id: RString) -> AnyObject {
            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(None, id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_without_base() -> RStoreId {
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().without_base();
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_with_base(base: RString) -> AnyObject {
            let base : PathBuf = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(pb) => pb,
                Err(e) => {
                    // TODO: Exception!
                    error!("Error: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().with_base(base);
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_into_pathbuf() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .clone()
                .into_pathbuf()
                // TODO: No unwraps
                .map(|pb| pb.to_str().map(String::from).unwrap())
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_exists() -> Boolean {
            Boolean::new(itself.get_data(&*STOREID_WRAPPER).exists())
        }

        fn r_storeid_to_str() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .to_str()
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_local() -> RString {
            let local = itself.get_data(&*STOREID_WRAPPER).local();
            let local = local.to_str().unwrap(); // TODO: No unwraps
            RString::new(local)
        }

    );

    pub fn setup() -> Class {
        let mut class = Class::new("RStoreId", None);
        class.define(|itself| {
            itself.def_self("new"          , r_storeid_new);
            itself.def_self("new_baseless" , r_storeid_new_baseless);

            itself.def("without_base"      , r_storeid_without_base);
            itself.def("with_base"         , r_storeid_with_base);
            itself.def("into_pathbuf"      , r_storeid_into_pathbuf);
            itself.def("exists"            , r_storeid_exists);
            itself.def("to_str"            , r_storeid_to_str);
            itself.def("local"             , r_storeid_local);
        });
        class
    }

}

#[allow(unused_variables)]
pub mod store {
    pub mod entry {
        use std::collections::BTreeMap;
        use std::error::Error;
        use std::ops::Deref;
        use std::ops::DerefMut;

        use ruru::{Class, Object, Array, Hash, Fixnum, Float, Symbol, AnyObject, Boolean, RString, VM};

        use libimagstore::store::FileLockEntry as FLE;
        use libimagstore::store::EntryHeader;
        use libimagstore::store::EntryContent;
        use libimagstore::store::Entry;

        pub struct FLECustomWrapper(Box<FLE<'static>>);

        impl Deref for FLECustomWrapper {
            type Target = Box<FLE<'static>>;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        impl DerefMut for FLECustomWrapper {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }

        wrappable_struct!(FLECustomWrapper, FileLockEntryWrapper, FLE_WRAPPER);
        class!(RFileLockEntry);

        wrappable_struct!(EntryHeader, EntryHeaderWrapper, ENTRY_HEADER_WRAPPER);
        class!(REntryHeader);
        methods!(
            REntryHeader,
            itself,

            fn r_entry_header_new() -> AnyObject {
                Class::from_existing("REntryHeader")
                    .wrap_data(EntryHeader::new(), &*ENTRY_HEADER_WRAPPER)
            }

            fn r_entry_header_insert(spec: RString, obj: AnyObject) -> Boolean {
                use toml::Value;
                use ruru::types::ValueType;

                fn do_insert(eh: &mut EntryHeader, spec: &str, v: Value) -> Boolean {
                    match eh.insert(spec, v) {
                        Ok(b) => Boolean::new(b),
                        Err(e) => {
                            VM::raise(Class::from_existing("RuntimeError"), e.description());
                            return Boolean::new(false);
                        }
                    }
                }

                fn to_value(obj: AnyObject) -> Result<Value, ()> {
                    match obj.value().ty() {
                        ValueType::Fixnum =>
                            Ok(Value::Integer(obj.try_convert_to::<Fixnum>().unwrap().to_i64())),

                        ValueType::Float =>
                            Ok(Value::Float(obj.try_convert_to::<Float>().unwrap().to_f64())),

                        ValueType::RString =>
                            Ok(Value::String(obj.try_convert_to::<RString>().unwrap().to_string())),

                        ValueType::Symbol =>
                            Ok(Value::String(obj.try_convert_to::<Symbol>().unwrap().to_string())),

                        _ => Err(()),
                    }
                }

                if let Err(ref error) = spec { // raise exception if "spec" is not a String
                    VM::raise(error.to_exception(), error.description());
                    return Boolean::new(false);
                }

                let spec = spec.unwrap().to_string(); // safe because of check above.
                let obj = obj.unwrap(); // possibly not safe... TODO
                match obj.value().ty() {
                    ValueType::Fixnum => {
                        let i = obj.try_convert_to::<Fixnum>().unwrap().to_i64();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Integer(i))
                    }

                    ValueType::Float => {
                        let f = obj.try_convert_to::<Float>().unwrap().to_f64();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Float(f))
                    }

                    ValueType::RString => {
                        let s = obj.try_convert_to::<RString>().unwrap().to_string();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::String(s))
                    }

                    ValueType::Symbol => {
                        let s = obj.try_convert_to::<Symbol>().unwrap().to_string();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::String(s))
                    }

                    ValueType::Array => {
                        let vals = obj.try_convert_to::<Array>()
                            .unwrap()
                            .into_iter()
                            .map(to_value)
                            .map(|el| {
                                let e_class = Class::from_existing("ArgumentError");
                                let err = "Arrays can only hold 'Fixnum', 'Float', 'String' or 'Symbol' in this API";
                                el.map_err(|_| VM::raise(e_class, err))
                            })
                            .filter_map(|e| e.ok())
                            .collect::<Vec<Value>>();

                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Array(vals))
                    }

                    ValueType::Hash => {
                        let mut btm = BTreeMap::new();
                        obj.try_convert_to::<Hash>()
                            .unwrap()
                            .each(|key, value| {
                                let key = match key.value().ty() {
                                    ValueType::RString => obj.try_convert_to::<RString>().unwrap().to_string(),
                                    ValueType::Symbol  => obj.try_convert_to::<Symbol>().unwrap().to_string(),
                                    _ => {
                                        let e_class = Class::from_existing("ArgumentError");
                                        let err = "Hash must have 'String' or 'Symbol' as Key";
                                        VM::raise(e_class, err);
                                        return; // from closure
                                    }
                                };
                                let value = match to_value(value) {
                                    Err(e) => {
                                        let e_class = Class::from_existing("ArgumentError");
                                        let err = "Hash must have 'Fixnum', 'Float', 'String' or 'Symbol' as value in this API";
                                        VM::raise(e_class, err);
                                        return; // from closure
                                    }
                                    Ok(v) => v,
                                };

                                btm.insert(key, value);
                            });

                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Table(btm))
                    }

                    ValueType::Nil => {
                        VM::raise(Class::from_existing("ArgumentError"), "Unexpected Argument 'nil'");
                        return Boolean::new(false);
                    }

                    _ => {
                        VM::raise(Class::from_existing("ArgumentError"), "Unexpected Argument Type");
                        return Boolean::new(false);
                    }
                }

            }

        );

        wrappable_struct!(EntryContent, EntryContentWrapper, ENTRY_CONTENT_WRAPPER);
        class!(REntryContent);

        wrappable_struct!(Entry, EntryWrapper, ENTRY_WRAPPER);
        class!(REntry);

        pub fn setup_filelockentry() -> Class {
            let mut class = Class::new("RFileLockEntry", None);
            class
        }

        pub fn setup_entryheader() -> Class {
            let mut class = Class::new("REntryHeader", None);
            class
        }

        pub fn setup_entrycontent() -> Class {
            let string = Class::from_existing("String");
            let mut class = Class::new("REntryContent", Some(&string));
            class
        }
    }

}

<commit_msg>Minify r_entry_header_insert()<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#[allow(unused_variables)]
pub mod storeid {
    use std::path::PathBuf;

    use ruru::{Class, Object, AnyObject, Boolean, RString, NilClass};

    use libimagstore::storeid::StoreId;

    wrappable_struct!(StoreId, StoreIdWrapper, STOREID_WRAPPER);
    class!(RStoreId);

    methods!(
        RStoreId,
        itself,

        fn r_storeid_new(base: RString, id: RString) -> AnyObject {
            let base = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(base) => base,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(Some(base), id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_new_baseless(id: RString) -> AnyObject {
            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(None, id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_without_base() -> RStoreId {
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().without_base();
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_with_base(base: RString) -> AnyObject {
            let base : PathBuf = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(pb) => pb,
                Err(e) => {
                    // TODO: Exception!
                    error!("Error: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().with_base(base);
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_into_pathbuf() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .clone()
                .into_pathbuf()
                // TODO: No unwraps
                .map(|pb| pb.to_str().map(String::from).unwrap())
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_exists() -> Boolean {
            Boolean::new(itself.get_data(&*STOREID_WRAPPER).exists())
        }

        fn r_storeid_to_str() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .to_str()
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_local() -> RString {
            let local = itself.get_data(&*STOREID_WRAPPER).local();
            let local = local.to_str().unwrap(); // TODO: No unwraps
            RString::new(local)
        }

    );

    pub fn setup() -> Class {
        let mut class = Class::new("RStoreId", None);
        class.define(|itself| {
            itself.def_self("new"          , r_storeid_new);
            itself.def_self("new_baseless" , r_storeid_new_baseless);

            itself.def("without_base"      , r_storeid_without_base);
            itself.def("with_base"         , r_storeid_with_base);
            itself.def("into_pathbuf"      , r_storeid_into_pathbuf);
            itself.def("exists"            , r_storeid_exists);
            itself.def("to_str"            , r_storeid_to_str);
            itself.def("local"             , r_storeid_local);
        });
        class
    }

}

#[allow(unused_variables)]
pub mod store {
    pub mod entry {
        use std::collections::BTreeMap;
        use std::error::Error;
        use std::ops::Deref;
        use std::ops::DerefMut;

        use ruru::{Class, Object, Array, Hash, Fixnum, Float, Symbol, AnyObject, Boolean, RString, VM};

        use libimagstore::store::FileLockEntry as FLE;
        use libimagstore::store::EntryHeader;
        use libimagstore::store::EntryContent;
        use libimagstore::store::Entry;

        pub struct FLECustomWrapper(Box<FLE<'static>>);

        impl Deref for FLECustomWrapper {
            type Target = Box<FLE<'static>>;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        impl DerefMut for FLECustomWrapper {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }

        wrappable_struct!(FLECustomWrapper, FileLockEntryWrapper, FLE_WRAPPER);
        class!(RFileLockEntry);

        wrappable_struct!(EntryHeader, EntryHeaderWrapper, ENTRY_HEADER_WRAPPER);
        class!(REntryHeader);
        methods!(
            REntryHeader,
            itself,

            fn r_entry_header_new() -> AnyObject {
                Class::from_existing("REntryHeader")
                    .wrap_data(EntryHeader::new(), &*ENTRY_HEADER_WRAPPER)
            }

            fn r_entry_header_insert(spec: RString, obj: AnyObject) -> Boolean {
                use toml::Value;
                use ruru::types::ValueType;
                use ruby_utils::IntoToml;

                if let Err(ref error) = spec { // raise exception if "spec" is not a String
                    VM::raise(error.to_exception(), error.description());
                    return Boolean::new(false);
                }

                let spec = spec.unwrap().to_string(); // safe because of check above.
                let obj = obj.unwrap(); // possibly not safe... TODO

                match itself.get_data(&*ENTRY_HEADER_WRAPPER).insert(&spec, obj.into_toml()) {
                    Ok(b) => Boolean::new(b),
                    Err(e) => {
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        return Boolean::new(false);
                    }
                }
            }

        );

        wrappable_struct!(EntryContent, EntryContentWrapper, ENTRY_CONTENT_WRAPPER);
        class!(REntryContent);

        wrappable_struct!(Entry, EntryWrapper, ENTRY_WRAPPER);
        class!(REntry);

        pub fn setup_filelockentry() -> Class {
            let mut class = Class::new("RFileLockEntry", None);
            class
        }

        pub fn setup_entryheader() -> Class {
            let mut class = Class::new("REntryHeader", None);
            class
        }

        pub fn setup_entrycontent() -> Class {
            let string = Class::from_existing("String");
            let mut class = Class::new("REntryContent", Some(&string));
            class
        }
    }

}

<|endoftext|>


<commit_before>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2018 LEE Dongjun <redongjun@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

extern crate glib;
use glib::prelude::*;

extern crate gstreamer as gst;
use gst::prelude::*;

extern crate gstreamer_app as gst_app;

use std::io::Write;
use std::sync::{Arc, Mutex};
use std::{thread, time};

extern crate gstthreadshare;

fn init() {
    use std::sync::{Once, ONCE_INIT};
    static INIT: Once = ONCE_INIT;

    INIT.call_once(|| {
        gst::init().unwrap();
        gstthreadshare::plugin_register_static().expect("gstthreadshare tcpclientsrc test");
    });
}

#[test]
fn test_push() {
    init();

    let handler = thread::spawn(move || {
        use std::net;

        let listener = net::TcpListener::bind("0.0.0.0:5000").unwrap();
        for stream in listener.incoming() {
            let buffer = [0; 160];
            let mut socket = stream.unwrap();
            for _ in 0..3 {
                let _ = socket.write(&buffer);
                thread::sleep(time::Duration::from_millis(20));
            }
            break;
        }
    });

    let pipeline = gst::Pipeline::new(None);

    let tcpclientsrc = gst::ElementFactory::make("ts-tcpclientsrc", None).unwrap();
    let appsink = gst::ElementFactory::make("appsink", None).unwrap();
    appsink.set_property("sync", &false).unwrap();
    appsink.set_property("async", &false).unwrap();

    pipeline.add_many(&[&tcpclientsrc, &appsink]).unwrap();
    tcpclientsrc.link(&appsink).unwrap();

    let caps = gst::Caps::new_simple("foo/bar", &[]);
    tcpclientsrc.set_property("caps", &caps).unwrap();
    tcpclientsrc.set_property("port", &(5000u32)).unwrap();

    appsink.set_property("emit-signals", &true).unwrap();

    let samples = Arc::new(Mutex::new(Vec::new()));

    let appsink = appsink.dynamic_cast::<gst_app::AppSink>().unwrap();
    let samples_clone = samples.clone();
    appsink.connect_new_sample(move |appsink| {
        let sample = appsink
            .emit("pull-sample", &[])
            .unwrap()
            .unwrap()
            .get::<gst::Sample>()
            .unwrap();

        let mut samples = samples_clone.lock().unwrap();
        samples.push(sample);
        Ok(gst::FlowSuccess::Ok)
    });

    pipeline.set_state(gst::State::Playing).unwrap();

    let mut eos = false;
    let bus = pipeline.get_bus().unwrap();
    while let Some(msg) = bus.timed_pop(5 * gst::SECOND) {
        use gst::MessageView;
        match msg.view() {
            MessageView::Eos(..) => {
                eos = true;
                break;
            }
            MessageView::Error(..) => unreachable!(),
            _ => (),
        }
    }

    assert!(eos);
    let samples = samples.lock().unwrap();
    for sample in samples.iter() {
        assert_eq!(Some(&caps), sample.get_caps().as_ref());
    }

    let total_received_size = samples.iter().fold(0, |acc, sample| {
        acc + sample.get_buffer().unwrap().get_size()
    });
    assert_eq!(total_received_size, 3 * 160);

    pipeline.set_state(gst::State::Null).unwrap();

    handler.join().unwrap();
}
<commit_msg>threadshare/tcpclientsrc: Fix build of test with changes gst::Sample API<commit_after>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2018 LEE Dongjun <redongjun@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

extern crate glib;
use glib::prelude::*;

extern crate gstreamer as gst;
use gst::prelude::*;

extern crate gstreamer_app as gst_app;

use std::io::Write;
use std::sync::{Arc, Mutex};
use std::{thread, time};

extern crate gstthreadshare;

fn init() {
    use std::sync::{Once, ONCE_INIT};
    static INIT: Once = ONCE_INIT;

    INIT.call_once(|| {
        gst::init().unwrap();
        gstthreadshare::plugin_register_static().expect("gstthreadshare tcpclientsrc test");
    });
}

#[test]
fn test_push() {
    init();

    let handler = thread::spawn(move || {
        use std::net;

        let listener = net::TcpListener::bind("0.0.0.0:5000").unwrap();
        for stream in listener.incoming() {
            let buffer = [0; 160];
            let mut socket = stream.unwrap();
            for _ in 0..3 {
                let _ = socket.write(&buffer);
                thread::sleep(time::Duration::from_millis(20));
            }
            break;
        }
    });

    let pipeline = gst::Pipeline::new(None);

    let tcpclientsrc = gst::ElementFactory::make("ts-tcpclientsrc", None).unwrap();
    let appsink = gst::ElementFactory::make("appsink", None).unwrap();
    appsink.set_property("sync", &false).unwrap();
    appsink.set_property("async", &false).unwrap();

    pipeline.add_many(&[&tcpclientsrc, &appsink]).unwrap();
    tcpclientsrc.link(&appsink).unwrap();

    let caps = gst::Caps::new_simple("foo/bar", &[]);
    tcpclientsrc.set_property("caps", &caps).unwrap();
    tcpclientsrc.set_property("port", &(5000u32)).unwrap();

    appsink.set_property("emit-signals", &true).unwrap();

    let samples = Arc::new(Mutex::new(Vec::new()));

    let appsink = appsink.dynamic_cast::<gst_app::AppSink>().unwrap();
    let samples_clone = samples.clone();
    appsink.connect_new_sample(move |appsink| {
        let sample = appsink
            .emit("pull-sample", &[])
            .unwrap()
            .unwrap()
            .get::<gst::Sample>()
            .unwrap();

        let mut samples = samples_clone.lock().unwrap();
        samples.push(sample);
        Ok(gst::FlowSuccess::Ok)
    });

    pipeline.set_state(gst::State::Playing).unwrap();

    let mut eos = false;
    let bus = pipeline.get_bus().unwrap();
    while let Some(msg) = bus.timed_pop(5 * gst::SECOND) {
        use gst::MessageView;
        match msg.view() {
            MessageView::Eos(..) => {
                eos = true;
                break;
            }
            MessageView::Error(..) => unreachable!(),
            _ => (),
        }
    }

    assert!(eos);
    let samples = samples.lock().unwrap();
    for sample in samples.iter() {
        assert_eq!(Some(caps.as_ref()), sample.get_caps());
    }

    let total_received_size = samples.iter().fold(0, |acc, sample| {
        acc + sample.get_buffer().unwrap().get_size()
    });
    assert_eq!(total_received_size, 3 * 160);

    pipeline.set_state(gst::State::Null).unwrap();

    handler.join().unwrap();
}
<|endoftext|>


<commit_before>extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;

use std::sync::mpsc;
use std::thread;

use r2d2_sqlite::SQLiteConnectionManager;
use rusqlite::{SQLITE_OPEN_CREATE, SQLITE_OPEN_READ_WRITE, SQLITE_OPEN_URI};

#[test]
fn test_basic() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        SQLITE_OPEN_URI | SQLITE_OPEN_CREATE | SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder()
        .max_size(2)
        .build(manager)
        .unwrap();

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        SQLITE_OPEN_URI | SQLITE_OPEN_CREATE | SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder()
        .max_size(1)
        .test_on_check_out(true)
        .build(manager)
        .unwrap();

    pool.get().unwrap();
}
<commit_msg>Rustfmt<commit_after>extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;

use std::sync::mpsc;
use std::thread;

use r2d2_sqlite::SQLiteConnectionManager;
use rusqlite::{SQLITE_OPEN_CREATE, SQLITE_OPEN_READ_WRITE, SQLITE_OPEN_URI};

#[test]
fn test_basic() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        SQLITE_OPEN_URI | SQLITE_OPEN_CREATE | SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder().max_size(2).build(manager).unwrap();

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        SQLITE_OPEN_URI | SQLITE_OPEN_CREATE | SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder()
        .max_size(1)
        .test_on_check_out(true)
        .build(manager)
        .unwrap();

    pool.get().unwrap();
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use mio;
use std::fmt;
use std::net::SocketAddr;

pub mod buffer_queue;
#[macro_use] pub mod metrics;
pub mod socket;
pub mod trie;
pub mod protocol;
pub mod http;
pub mod backends;
pub mod retry;

#[cfg(feature = "splice")]
mod splice;

pub mod tcp;
pub mod proxy;
pub mod session;

#[cfg(feature = "use_openssl")]
pub mod https_openssl;

#[cfg(feature = "use_openssl")]
pub mod https {
  pub type ServerConfiguration = https_openssl::ServerConfiguration;
  pub type TlsClient           = https_openssl::TlsClient;

  pub use super::https_openssl::configuration::start;
}

#[cfg(not(feature = "use_openssl"))]
pub mod https_rustls;

#[cfg(not(feature = "use_openssl"))]
pub mod https {
  pub type ServerConfiguration = super::https_rustls::configuration::ServerConfiguration;
  pub type TlsClient           = super::https_rustls::client::TlsClient;

  pub use super::https_rustls::configuration::start;
}

use mio::Token;

use self::retry::RetryPolicy;

pub type AppId = String;

#[derive(Debug,Clone,Copy)]
pub enum Protocol {
  HTTP,
  HTTPS,
  TCP
}

#[derive(Debug,PartialEq,Eq)]
pub enum RequiredEvents {
  FrontReadBackNone,
  FrontWriteBackNone,
  FrontReadWriteBackNone,
  FrontNoneBackNone,
  FrontReadBackRead,
  FrontWriteBackRead,
  FrontReadWriteBackRead,
  FrontNoneBackRead,
  FrontReadBackWrite,
  FrontWriteBackWrite,
  FrontReadWriteBackWrite,
  FrontNoneBackWrite,
  FrontReadBackReadWrite,
  FrontWriteBackReadWrite,
  FrontReadWriteBackReadWrite,
  FrontNoneBackReadWrite,
}

impl RequiredEvents {

  pub fn front_readable(&self) -> bool {
    match *self {
      RequiredEvents::FrontReadBackNone
      | RequiredEvents:: FrontReadWriteBackNone
      | RequiredEvents:: FrontReadBackRead
      | RequiredEvents:: FrontReadWriteBackRead
      | RequiredEvents:: FrontReadBackWrite
      | RequiredEvents:: FrontReadWriteBackWrite
      | RequiredEvents:: FrontReadBackReadWrite
      | RequiredEvents:: FrontReadWriteBackReadWrite => true,
      _ => false
    }
  }

  pub fn front_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontWriteBackNone
        | RequiredEvents::FrontReadWriteBackNone
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_readable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackRead
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontNoneBackRead
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackWrite
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontNoneBackWrite
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }
}

#[derive(Debug,PartialEq,Eq)]
pub enum ClientResult {
  CloseClient,
  CloseBackend,
  CloseBoth,
  Continue,
  ConnectBackend
}

#[derive(Debug,PartialEq,Eq)]
pub enum ConnectionError {
  NoHostGiven,
  NoRequestLineGiven,
  HostNotFound,
  NoBackendAvailable,
  ToBeDefined,
  HttpsRedirect
}

#[derive(Debug,PartialEq,Eq)]
pub enum SocketType {
  Listener,
  FrontClient,
  BackClient,
}

#[derive(Debug,PartialEq,Eq)]
pub enum BackendStatus {
  Normal,
  Closing,
  Closed,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Backend {
  pub id:                 u32,
  pub instance_id:        String,
  pub address:            SocketAddr,
  pub status:             BackendStatus,
  pub retry_policy:       retry::RetryPolicyWrapper,
  pub active_connections: usize,
  pub failures:           usize,
}

impl Backend {
  pub fn new(instance_id: &str, addr: SocketAddr, id: u32) -> Backend {
    let desired_policy = retry::ExponentialBackoffPolicy::new(10);
    Backend {
      id:                 id,
      instance_id:        instance_id.to_string(),
      address:            addr,
      status:             BackendStatus::Normal,
      retry_policy:       desired_policy.into(),
      active_connections: 0,
      failures:           0,
    }
  }

  pub fn set_closing(&mut self) {
    self.status = BackendStatus::Closing;
  }

  pub fn retry_policy(&mut self) -> &mut retry::RetryPolicyWrapper {
    &mut self.retry_policy
  }

  pub fn can_open(&self) -> bool {
    if let Some(action) = self.retry_policy.can_try() {
      self.status == BackendStatus::Normal && action == retry::RetryAction::OKAY
    } else {
      false
    }
  }

  pub fn inc_connections(&mut self) -> Option<usize> {
    if self.status == BackendStatus::Normal {
      self.active_connections += 1;
      Some(self.active_connections)
    } else {
      None
    }
  }

  pub fn dec_connections(&mut self) -> Option<usize> {
    if self.active_connections == 0 {
      self.status = BackendStatus::Closed;
      return None;
    }

    match self.status {
      BackendStatus::Normal => {
        self.active_connections -= 1;
        Some(self.active_connections)
      }
      BackendStatus::Closed  => None,
      BackendStatus::Closing => {
        self.active_connections -= 1;
        if self.active_connections == 0 {
          self.status = BackendStatus::Closed;
          None
        } else {
          Some(self.active_connections)
        }
      },
    }
  }

  pub fn try_connect(&mut self) -> Result<mio::tcp::TcpStream, ConnectionError> {
    if self.status != BackendStatus::Normal {
      return Err(ConnectionError::NoBackendAvailable);
    }

    //FIXME: what happens if the connect() call fails with EINPROGRESS?
    let conn = mio::tcp::TcpStream::connect(&self.address).map_err(|_| ConnectionError::NoBackendAvailable);
    if conn.is_ok() {
      //self.retry_policy.succeed();
      self.inc_connections();
    } else {
      self.retry_policy.fail();
      self.failures += 1;
    }

    conn
  }
}

<commit_msg>Fix compilation with use_openssl feature<commit_after>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use mio;
use std::fmt;
use std::net::SocketAddr;

pub mod buffer_queue;
#[macro_use] pub mod metrics;
pub mod socket;
pub mod trie;
pub mod protocol;
pub mod http;
pub mod backends;
pub mod retry;

#[cfg(feature = "splice")]
mod splice;

pub mod tcp;
pub mod proxy;
pub mod session;

#[cfg(feature = "use_openssl")]
pub mod https_openssl;

#[cfg(feature = "use_openssl")]
pub mod https {
  pub type ServerConfiguration = super::https_openssl::ServerConfiguration;
  pub type TlsClient           = super::https_openssl::TlsClient;

  pub use super::https_openssl::start;
}

#[cfg(not(feature = "use_openssl"))]
pub mod https_rustls;

#[cfg(not(feature = "use_openssl"))]
pub mod https {
  pub type ServerConfiguration = super::https_rustls::configuration::ServerConfiguration;
  pub type TlsClient           = super::https_rustls::client::TlsClient;

  pub use super::https_rustls::configuration::start;
}

use mio::Token;

use self::retry::RetryPolicy;

pub type AppId = String;

#[derive(Debug,Clone,Copy)]
pub enum Protocol {
  HTTP,
  HTTPS,
  TCP
}

#[derive(Debug,PartialEq,Eq)]
pub enum RequiredEvents {
  FrontReadBackNone,
  FrontWriteBackNone,
  FrontReadWriteBackNone,
  FrontNoneBackNone,
  FrontReadBackRead,
  FrontWriteBackRead,
  FrontReadWriteBackRead,
  FrontNoneBackRead,
  FrontReadBackWrite,
  FrontWriteBackWrite,
  FrontReadWriteBackWrite,
  FrontNoneBackWrite,
  FrontReadBackReadWrite,
  FrontWriteBackReadWrite,
  FrontReadWriteBackReadWrite,
  FrontNoneBackReadWrite,
}

impl RequiredEvents {

  pub fn front_readable(&self) -> bool {
    match *self {
      RequiredEvents::FrontReadBackNone
      | RequiredEvents:: FrontReadWriteBackNone
      | RequiredEvents:: FrontReadBackRead
      | RequiredEvents:: FrontReadWriteBackRead
      | RequiredEvents:: FrontReadBackWrite
      | RequiredEvents:: FrontReadWriteBackWrite
      | RequiredEvents:: FrontReadBackReadWrite
      | RequiredEvents:: FrontReadWriteBackReadWrite => true,
      _ => false
    }
  }

  pub fn front_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontWriteBackNone
        | RequiredEvents::FrontReadWriteBackNone
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_readable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackRead
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontNoneBackRead
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackWrite
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontNoneBackWrite
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }
}

#[derive(Debug,PartialEq,Eq)]
pub enum ClientResult {
  CloseClient,
  CloseBackend,
  CloseBoth,
  Continue,
  ConnectBackend
}

#[derive(Debug,PartialEq,Eq)]
pub enum ConnectionError {
  NoHostGiven,
  NoRequestLineGiven,
  HostNotFound,
  NoBackendAvailable,
  ToBeDefined,
  HttpsRedirect
}

#[derive(Debug,PartialEq,Eq)]
pub enum SocketType {
  Listener,
  FrontClient,
  BackClient,
}

#[derive(Debug,PartialEq,Eq)]
pub enum BackendStatus {
  Normal,
  Closing,
  Closed,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Backend {
  pub id:                 u32,
  pub instance_id:        String,
  pub address:            SocketAddr,
  pub status:             BackendStatus,
  pub retry_policy:       retry::RetryPolicyWrapper,
  pub active_connections: usize,
  pub failures:           usize,
}

impl Backend {
  pub fn new(instance_id: &str, addr: SocketAddr, id: u32) -> Backend {
    let desired_policy = retry::ExponentialBackoffPolicy::new(10);
    Backend {
      id:                 id,
      instance_id:        instance_id.to_string(),
      address:            addr,
      status:             BackendStatus::Normal,
      retry_policy:       desired_policy.into(),
      active_connections: 0,
      failures:           0,
    }
  }

  pub fn set_closing(&mut self) {
    self.status = BackendStatus::Closing;
  }

  pub fn retry_policy(&mut self) -> &mut retry::RetryPolicyWrapper {
    &mut self.retry_policy
  }

  pub fn can_open(&self) -> bool {
    if let Some(action) = self.retry_policy.can_try() {
      self.status == BackendStatus::Normal && action == retry::RetryAction::OKAY
    } else {
      false
    }
  }

  pub fn inc_connections(&mut self) -> Option<usize> {
    if self.status == BackendStatus::Normal {
      self.active_connections += 1;
      Some(self.active_connections)
    } else {
      None
    }
  }

  pub fn dec_connections(&mut self) -> Option<usize> {
    if self.active_connections == 0 {
      self.status = BackendStatus::Closed;
      return None;
    }

    match self.status {
      BackendStatus::Normal => {
        self.active_connections -= 1;
        Some(self.active_connections)
      }
      BackendStatus::Closed  => None,
      BackendStatus::Closing => {
        self.active_connections -= 1;
        if self.active_connections == 0 {
          self.status = BackendStatus::Closed;
          None
        } else {
          Some(self.active_connections)
        }
      },
    }
  }

  pub fn try_connect(&mut self) -> Result<mio::tcp::TcpStream, ConnectionError> {
    if self.status != BackendStatus::Normal {
      return Err(ConnectionError::NoBackendAvailable);
    }

    //FIXME: what happens if the connect() call fails with EINPROGRESS?
    let conn = mio::tcp::TcpStream::connect(&self.address).map_err(|_| ConnectionError::NoBackendAvailable);
    if conn.is_ok() {
      //self.retry_policy.succeed();
      self.inc_connections();
    } else {
      self.retry_policy.fail();
      self.failures += 1;
    }

    conn
  }
}

<|endoftext|>


<commit_before>#![feature(slicing_syntax)]
#![allow(unstable)]
extern crate jit;

use jit::*;
use jit::typecs::UBYTE;
use std::cell::RefCell;
use std::io;
use std::io::fs::File;
use std::mem;
use std::os;
use std::path::Path;
use std::rc::Rc;

macro_rules! count(
    ($func:ident, $code:ident, $curr:ident) => ({
        let mut amount = 1us;
        while $code.peek() == Some(&$curr) {
            amount += 1;
            $code.next();
        }
        $func.insn_of(&amount)
    })
);

static PROMPT:&'static str = "> ";
type WrappedLoop<'a> = Rc<RefCell<Loop<'a>>>;
struct Loop<'a> {
    start: Label<'a>,
    end: Label<'a>,
    parent: Option<WrappedLoop<'a>>
}
impl<'a> Loop<'a> {
    fn new(func: &UncompiledFunction<'a>, current_loop: Option<WrappedLoop<'a>>) -> Loop<'a> {
        let mut new_loop = Loop {
            start: Label::new(func),
            end: Label::new(func),
            parent: current_loop
        };
        func.insn_label(&mut new_loop.start);
        new_loop
    }
    fn end(&mut self, func: &UncompiledFunction<'a>) -> Option<WrappedLoop<'a>> {
        func.insn_branch(&mut self.start);
        func.insn_label(&mut self.end);
        let mut parent = None;
        mem::swap(&mut parent, &mut self.parent);
        parent
    }
}

fn compile<'a>(func: &UncompiledFunction<'a>, code: &str) {
    let ubyte = UBYTE.get();
    let putchar_sig = get::<fn(u8)>();
    let readchar_sig = get::<fn() -> u8>();
    let data = func[0];
    let mut current_loop = None;
    let mut code = code.chars().peekable();
    while let Some(c) = code.next() {
        match c {
            '>' => {
                let amount = count!(func, code, c);
                let new_value = data + amount;
                func.insn_store(data, new_value);
            },
            '<' => {
                let amount = count!(func, code, c);
                let new_value = data - amount;
                func.insn_store(data, new_value);
            },
            '+' => {
                let amount = count!(func, code, c);
                let mut value = func.insn_load_relative(data, 0, ubyte.clone());
                value = value + amount;
                value = func.insn_convert(value, ubyte.clone(), false);
                func.insn_store_relative(data, 0, value)
            },
            '-' => {
                let amount = count!(func, code, c);
                let mut value = func.insn_load_relative(data, 0, ubyte.clone());
                value = value - amount;
                value = func.insn_convert(value, ubyte.clone(), false);
                func.insn_store_relative(data, 0, value)
            },
            '.' => {
                extern fn putchar(c: u8) {
                    io::stdout().write_u8(c).unwrap();
                }
                let value = func.insn_load_relative(data, 0, ubyte.clone());
                func.insn_call_native1(Some("putchar"), putchar, putchar_sig.clone(), [value], flags::NO_THROW);
            },
            ',' => {
                extern fn readchar() -> u8 {
                    io::stdin().read_byte().unwrap()
                }
                let value = func.insn_call_native0(Some("readchar"), readchar, readchar_sig.clone(), flags::NO_THROW);
                func.insn_store_relative(data, 0, value);
            },
            '[' => {
                let wrapped_loop = Rc::new(RefCell::new(Loop::new(func, current_loop)));
                let tmp = func.insn_load_relative(data, 0, ubyte.clone());
                {
                    let mut borrow = wrapped_loop.borrow_mut();
                    func.insn_branch_if_not(tmp, &mut borrow.end);
                }
                current_loop = Some(wrapped_loop);
            },
            ']' => {
                current_loop = if let Some(ref inner_loop) = current_loop {
                    let mut borrow = inner_loop.borrow_mut();
                    borrow.end(func)
                } else {
                    None
                }
            },
            _ => ()
        }
    };
    func.insn_default_return();
}
fn run(ctx: &mut Context, code: &str) {
    let sig = get::<fn(*mut u8)>();
    let func = ctx.build_func(sig, |func| compile(func, code));
    func.with(|func:extern fn(*mut u8)| {
        let mut data: [u8; 3000] = unsafe { mem::zeroed() };
        func(data.as_mut_ptr());
    });
}
fn main() {
    let mut ctx = Context::new();
    match os::args().tail() {
        [ref script] => {
            let ref script = Path::new(script.as_slice());
            let contents = File::open(script).unwrap().read_to_string().unwrap();
            run(&mut ctx, contents.as_slice());
        },
        [] => {
            io::print(PROMPT);
            for line in io::stdin().lock().lines() {
                run(&mut ctx, line.unwrap().as_slice());
                io::print(PROMPT);
            }
        },
        _ => panic!("Invalid args for Brainfuck VM")
    }
}<commit_msg>Use `count` as method instead of macro<commit_after>#![feature(slicing_syntax)]
#![allow(unstable)]
extern crate jit;

use jit::*;
use jit::typecs::UBYTE;
use std::cell::RefCell;
use std::io;
use std::io::fs::File;
use std::iter::Peekable;
use std::mem;
use std::os;
use std::path::Path;
use std::rc::Rc;

static PROMPT:&'static str = "> ";
type WrappedLoop<'a> = Rc<RefCell<Loop<'a>>>;
struct Loop<'a> {
    start: Label<'a>,
    end: Label<'a>,
    parent: Option<WrappedLoop<'a>>
}
impl<'a> Loop<'a> {
    fn new(func: &UncompiledFunction<'a>, current_loop: Option<WrappedLoop<'a>>) -> Loop<'a> {
        let mut new_loop = Loop {
            start: Label::new(func),
            end: Label::new(func),
            parent: current_loop
        };
        func.insn_label(&mut new_loop.start);
        new_loop
    }
    fn end(&mut self, func: &UncompiledFunction<'a>) -> Option<WrappedLoop<'a>> {
        func.insn_branch(&mut self.start);
        func.insn_label(&mut self.end);
        let mut parent = None;
        mem::swap(&mut parent, &mut self.parent);
        parent
    }
}

fn count<'a, I>(func: &UncompiledFunction<'a>, code: &mut Peekable<char, I>, curr:char) -> Value<'a> where I:Iterator<Item=char> {
    let mut amount = 1us;
    while code.peek() == Some(&curr) {
        amount += 1;
        code.next();
    }
    func.insn_of(&amount)
}

fn compile<'a>(func: &UncompiledFunction<'a>, code: &str) {
    let ubyte = UBYTE.get();
    let putchar_sig = get::<fn(u8)>();
    let readchar_sig = get::<fn() -> u8>();
    let data = func[0];
    let mut current_loop = None;
    let mut code = code.chars().peekable();
    while let Some(c) = code.next() {
        match c {
            '>' => {
                let amount = count(func, &mut code, c);
                let new_value = data + amount;
                func.insn_store(data, new_value);
            },
            '<' => {
                let amount = count(func, &mut code, c);
                let new_value = data - amount;
                func.insn_store(data, new_value);
            },
            '+' => {
                let amount = count(func, &mut code, c);
                let mut value = func.insn_load_relative(data, 0, ubyte.clone());
                value = value + amount;
                value = func.insn_convert(value, ubyte.clone(), false);
                func.insn_store_relative(data, 0, value)
            },
            '-' => {
                let amount = count(func, &mut code, c);
                let mut value = func.insn_load_relative(data, 0, ubyte.clone());
                value = value - amount;
                value = func.insn_convert(value, ubyte.clone(), false);
                func.insn_store_relative(data, 0, value)
            },
            '.' => {
                extern fn putchar(c: u8) {
                    io::stdout().write_u8(c).unwrap();
                }
                let value = func.insn_load_relative(data, 0, ubyte.clone());
                func.insn_call_native1(Some("putchar"), putchar, putchar_sig.clone(), [value], flags::NO_THROW);
            },
            ',' => {
                extern fn readchar() -> u8 {
                    io::stdin().read_byte().unwrap()
                }
                let value = func.insn_call_native0(Some("readchar"), readchar, readchar_sig.clone(), flags::NO_THROW);
                func.insn_store_relative(data, 0, value);
            },
            '[' => {
                let wrapped_loop = Rc::new(RefCell::new(Loop::new(func, current_loop)));
                let tmp = func.insn_load_relative(data, 0, ubyte.clone());
                {
                    let mut borrow = wrapped_loop.borrow_mut();
                    func.insn_branch_if_not(tmp, &mut borrow.end);
                }
                current_loop = Some(wrapped_loop);
            },
            ']' => {
                current_loop = if let Some(ref inner_loop) = current_loop {
                    let mut borrow = inner_loop.borrow_mut();
                    borrow.end(func)
                } else {
                    None
                }
            },
            _ => ()
        }
    };
    func.insn_default_return();
}
fn run(ctx: &mut Context, code: &str) {
    let sig = get::<fn(*mut u8)>();
    let func = ctx.build_func(sig, |func| compile(func, code));
    func.with(|func:extern fn(*mut u8)| {
        let mut data: [u8; 3000] = unsafe { mem::zeroed() };
        func(data.as_mut_ptr());
    });
}
fn main() {
    let mut ctx = Context::new();
    match os::args().tail() {
        [ref script] => {
            let ref script = Path::new(script.as_slice());
            let contents = File::open(script).unwrap().read_to_string().unwrap();
            run(&mut ctx, contents.as_slice());
        },
        [] => {
            io::print(PROMPT);
            for line in io::stdin().lock().lines() {
                run(&mut ctx, line.unwrap().as_slice());
                io::print(PROMPT);
            }
        },
        _ => panic!("Invalid args for Brainfuck VM")
    }
}<|endoftext|>