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

use std::thread::{self,Thread,Builder};
use std::sync::mpsc::{self,channel,Receiver};
use mio::tcp::*;
use mio::*;
use bytes::{ByteBuf,MutByteBuf};
use std::collections::HashMap;
use std::io::{self,Read,ErrorKind};
use nom::HexDisplay;
use std::error::Error;
use mio::util::Slab;
use std::io::Write;
use std::str::FromStr;
use std::marker::PhantomData;
use std::fmt::Debug;
use time::precise_time_ns;
use rand::random;

use network::{ClientResult,ServerMessage,ConnectionError,SocketType,socket_type,ProxyOrder,RequiredEvents};
use network::metrics::{METRICS,ProxyMetrics};

use messages::{TcpFront,Command,Instance};

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

pub trait ProxyClient {
  fn front_socket(&self) -> &TcpStream;
  fn back_socket(&self)  -> Option<&TcpStream>;
  fn front_token(&self)  -> Option<Token>;
  fn back_token(&self)   -> Option<Token>;
  fn set_back_socket(&mut self, TcpStream);
  fn set_front_token(&mut self, token: Token);
  fn set_back_token(&mut self, token: Token);
  fn front_timeout(&mut self) -> Option<Timeout>;
  fn back_timeout(&mut self)  -> Option<Timeout>;
  fn set_front_timeout(&mut self, timeout: Timeout);
  fn set_back_timeout(&mut self, timeout: Timeout);
  fn set_tokens(&mut self, token: Token, backend: Token);
  fn front_hup(&mut self)     -> ClientResult;
  fn back_hup(&mut self)      -> ClientResult;
  fn readable(&mut self)      -> (RequiredEvents, ClientResult);
  fn writable(&mut self)      -> (RequiredEvents, ClientResult);
  fn back_readable(&mut self) -> (RequiredEvents, ClientResult);
  fn back_writable(&mut self) -> (RequiredEvents, ClientResult);
  fn remove_backend(&mut self);
}

pub trait ProxyConfiguration<Server:Handler,Client> {
  fn connect_to_backend(&mut self, client:&mut Client) ->Result<TcpStream,ConnectionError>;
  fn notify(&mut self, event_loop: &mut EventLoop<Server>, message: ProxyOrder);
  fn accept(&mut self, token: Token) -> Option<(Client, bool)>;
}

pub struct Server<ServerConfiguration,Client> {
  configuration:   ServerConfiguration,
  clients:         Slab<Client>,
  backend:         Slab<ClientToken>,
  max_listeners:   usize,
  max_connections: usize,
  front_timeout:   u64,
  back_timeout:    u64,
}

impl<ServerConfiguration:ProxyConfiguration<Server<ServerConfiguration,Client>, Client>,Client:ProxyClient> Server<ServerConfiguration,Client> {
  pub fn new(max_listeners: usize, max_connections: usize, configuration: ServerConfiguration) -> Self {
    Server {
      configuration:   configuration,
      clients:         Slab::new_starting_at(Token(max_listeners), max_connections),
      backend:         Slab::new_starting_at(Token(max_listeners+max_connections), max_connections),
      max_listeners:   max_listeners,
      max_connections: max_connections,
      front_timeout:   DEFAULT_FRONT_TIMEOUT,
      back_timeout:    DEFAULT_BACK_TIMEOUT,
    }
  }

  pub fn configuration(&mut self) -> &mut ServerConfiguration {
    &mut self.configuration
  }

  pub fn close_client(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    self.clients[token].front_socket().shutdown(Shutdown::Both);
    event_loop.deregister(self.clients[token].front_socket());
    if let Some(sock) = self.clients[token].back_socket() {
      sock.shutdown(Shutdown::Both);
      event_loop.deregister(sock);
    }

    if let Some(backend_token) = self.clients[token].back_token() {
      if self.backend.contains(backend_token) {
        self.backend.remove(backend_token);
      }
    }
    self.clients.remove(token);
  }

  pub fn close_backend(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    if let Some(backend_token) = self.clients[token].back_token() {
      if self.backend.contains(backend_token) {
        self.backend.remove(backend_token);
        self.clients[token].remove_backend();
      }
    }
  }

  pub fn accept(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    if let Some((client, should_connect)) = self.configuration.accept(token) {
      if let Ok(client_token) = self.clients.insert(client) {
        event_loop.register(self.clients[client_token].front_socket(), client_token, EventSet::readable(), PollOpt::edge());
        &self.clients[client_token].set_front_token(client_token);
        if let Ok(timeout) = event_loop.timeout_ms(client_token.as_usize(), self.front_timeout) {
          &self.clients[client_token].set_front_timeout(timeout);
        }
        METRICS.lock().unwrap().gauge("accept", 1);
        if should_connect {
          self.connect_to_backend(event_loop, client_token);
        }
      } else {
        error!("could not add client to slab");
      }
    } else {
      error!("could not create a client");
    }
  }

  pub fn connect_to_backend(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    match self.configuration.connect_to_backend(&mut self.clients[token]) {
      Ok(socket) => {
        if let Ok(backend_token) = self.backend.insert(token) {
          self.clients[token].set_back_socket(socket);
          self.clients[token].set_back_token(backend_token);

          if let Some(sock) = self.clients[token].back_socket() {
            event_loop.register(sock, backend_token, EventSet::writable(), PollOpt::edge());
          }
          if let Ok(timeout) = event_loop.timeout_ms(backend_token.as_usize(), self.back_timeout) {
            &self.clients[token].set_back_timeout(timeout);
          }
          return;
        }
      },
      Err(ConnectionError::HostNotFound) | Err(ConnectionError::NoBackendAvailable) => {
        let mut front_interest = EventSet::hup();
        front_interest.insert(EventSet::writable());
        let client = &self.clients[token];

        event_loop.reregister(client.front_socket(), token, front_interest, PollOpt::level() | PollOpt::oneshot());
      },
      _ => self.close_client(event_loop, token),
    }
  }

  pub fn get_client_token(&self, token: Token) -> Option<Token> {
    if token.as_usize() < self.max_listeners {
      None
    } else if token.as_usize() < self.max_listeners + self.max_connections && self.clients.contains(token) {
      Some(token)
    } else if token.as_usize() < self.max_listeners + 2 * self.max_connections && self.backend.contains(token) {
      if self.clients.contains(self.backend[token]) {
        Some(self.backend[token])
      } else {
        None
      }
    } else {
      None
    }
  }

  pub fn interpret_client_order(&mut self, event_loop: &mut EventLoop<Self>, token: Token, order: (RequiredEvents, ClientResult)) {
    //println!("ORDER: {:?}", order);
    match order.1 {
      ClientResult::CloseClient      => self.close_client(event_loop, token),
      ClientResult::CloseBackend     => self.close_backend(event_loop, token),
      ClientResult::CloseBothSuccess => self.close_client(event_loop, token),
      ClientResult::CloseBothFailure => self.close_client(event_loop, token),
      ClientResult::ConnectBackend   => {
        let mut front_interest = EventSet::hup();
        let mut back_interest  = EventSet::hup();
        front_interest.insert(EventSet::readable());
        back_interest.insert(EventSet::writable());
        self.reregister(event_loop, token, front_interest, back_interest);
        self.connect_to_backend(event_loop, token)
      },
      ClientResult::Continue         => {
        let mut front_interest = EventSet::hup();
        let mut back_interest  = EventSet::hup();
        if order.0.front_readable() {
          front_interest.insert(EventSet::readable());
        }
        if order.0.front_writable() {
          front_interest.insert(EventSet::writable());
        }
        if order.0.back_readable() {
          back_interest.insert(EventSet::readable());
        }
        if order.0.back_writable() {
          back_interest.insert(EventSet::writable());
        }
        self.reregister(event_loop, token, front_interest, back_interest)
      }
    }
  }

  fn reregister(&self, event_loop: &mut EventLoop<Self>, token: Token, front_interest: EventSet, back_interest: EventSet) {
    let client = &self.clients[token];

    if let Some(frontend_token) = client.front_token() {
      event_loop.reregister(client.front_socket(), frontend_token, front_interest, PollOpt::level() | PollOpt::oneshot());
    }
     if let Some(backend_token) = client.back_token() {
       if let Some(sock) = client.back_socket() {
         event_loop.reregister(sock, backend_token, back_interest, PollOpt::level() | PollOpt::oneshot());
       }
     }
  }
}

impl<ServerConfiguration:ProxyConfiguration<Server<ServerConfiguration,Client>, Client>,Client:ProxyClient> Handler for Server<ServerConfiguration,Client> {
  type Timeout = usize;
  type Message = ProxyOrder;

  fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
    trace!("{:?} got events: {:?}", token, events);
    if events.is_readable() {
      trace!("{:?} is readable", token);

      match socket_type(token, self.max_listeners, self.max_connections) {
        Some(SocketType::Listener) => {
          self.accept(event_loop, token)
        }

        Some(SocketType::FrontClient) => {
          if self.clients.contains(token) {
            let order = self.clients[token].readable();

            // FIXME: should clear the timeout only if data was consumed
            if let Some(timeout) = self.clients[token].front_timeout() {
              //println!("[{}] clearing timeout", token.as_usize());
              event_loop.clear_timeout(timeout);
            }
            if let Ok(timeout) = event_loop.timeout_ms(token.as_usize(), self.front_timeout) {
              //println!("[{}] resetting timeout", token.as_usize());
              &self.clients[token].set_front_timeout(timeout);
            }

            self.interpret_client_order(event_loop, token, order);
          } else {
            info!("client {:?} was removed", token);
          }
        }

        Some(SocketType::BackClient) => {
          if let Some(tok) = self.get_client_token(token) {
            let order = self.clients[tok].back_readable();

            // FIXME: should clear the timeout only if data was consumed
            if let Some(timeout) = self.clients[tok].back_timeout() {
              //println!("[{}] clearing timeout", token.as_usize());
              event_loop.clear_timeout(timeout);
            }
            if let Ok(timeout) = event_loop.timeout_ms(token.as_usize(), self.back_timeout) {
              //println!("[{}] resetting timeout", token.as_usize());
              &self.clients[tok].set_back_timeout(timeout);
            }

            self.interpret_client_order(event_loop, tok, order);
          }
        }

        None => {}
      }
    }

    if events.is_writable() {
      trace!("{:?} is writable", token);

      match socket_type(token, self.max_listeners, self.max_connections) {
        Some(SocketType::Listener) => {
          error!("received writable for listener {:?}, this should not happen", token);
        }

        Some(SocketType::FrontClient) => {
          if self.clients.contains(token) {
            let order = self.clients[token].writable();
            trace!("interpreting client order {:?}", order);
            self.interpret_client_order(event_loop, token, order);
          } else {
            info!("client {:?} was removed", token);
          }
        }

        Some(SocketType::BackClient) => {
          if let Some(tok) = self.get_client_token(token) {
            let order = self.clients[tok].back_writable();
            self.interpret_client_order(event_loop, tok, order);
          }
        }

        None => {}
      }
    }

    if events.is_hup() {
      match socket_type(token, self.max_listeners, self.max_connections) {
        Some(SocketType::Listener) => {
          error!("should not happen: server {:?} closed", token);
        }

        Some(SocketType::FrontClient) => {
          if self.clients.contains(token) {
            if self.clients[token].front_hup() == ClientResult::CloseClient {
              self.close_client(event_loop, token);
            }
          } else {
            info!("client {:?} was removed", token);
          }
        }

        Some(SocketType::BackClient) => {
          if let Some(tok) = self.get_client_token(token) {
            if self.clients[tok].front_hup() == ClientResult::CloseClient {
              self.close_client(event_loop, tok);
            }
          }
        }

        None => {}
      }
    }
  }

  fn notify(&mut self, event_loop: &mut EventLoop<Self>, message: Self::Message) {
    self.configuration.notify(event_loop, message);
  }

  fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
    let token = Token(timeout);
    match socket_type(token, self.max_listeners, self.max_connections) {
      Some(SocketType::Listener) => {
        error!("the listener socket should have no timeout set");
      },
      Some(SocketType::FrontClient) => {
        if self.clients.contains(token) {
          error!("frontend [{}] got timeout, closing", timeout);
          self.close_client(event_loop, token);
        }
      },
      Some(SocketType::BackClient) => {
        if let Some(tok) = self.get_client_token(token) {
          error!("backend [{}] got timeout, closing", timeout);
          self.close_client(event_loop, tok);
        }
      }
      None => {}
    }
  }

  fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
    warn!("interrupted");
  }
}

<commit_msg>a socket timeout may not be an error<commit_after>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use std::thread::{self,Thread,Builder};
use std::sync::mpsc::{self,channel,Receiver};
use mio::tcp::*;
use mio::*;
use bytes::{ByteBuf,MutByteBuf};
use std::collections::HashMap;
use std::io::{self,Read,ErrorKind};
use nom::HexDisplay;
use std::error::Error;
use mio::util::Slab;
use std::io::Write;
use std::str::FromStr;
use std::marker::PhantomData;
use std::fmt::Debug;
use time::precise_time_ns;
use rand::random;

use network::{ClientResult,ServerMessage,ConnectionError,SocketType,socket_type,ProxyOrder,RequiredEvents};
use network::metrics::{METRICS,ProxyMetrics};

use messages::{TcpFront,Command,Instance};

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

pub trait ProxyClient {
  fn front_socket(&self) -> &TcpStream;
  fn back_socket(&self)  -> Option<&TcpStream>;
  fn front_token(&self)  -> Option<Token>;
  fn back_token(&self)   -> Option<Token>;
  fn set_back_socket(&mut self, TcpStream);
  fn set_front_token(&mut self, token: Token);
  fn set_back_token(&mut self, token: Token);
  fn front_timeout(&mut self) -> Option<Timeout>;
  fn back_timeout(&mut self)  -> Option<Timeout>;
  fn set_front_timeout(&mut self, timeout: Timeout);
  fn set_back_timeout(&mut self, timeout: Timeout);
  fn set_tokens(&mut self, token: Token, backend: Token);
  fn front_hup(&mut self)     -> ClientResult;
  fn back_hup(&mut self)      -> ClientResult;
  fn readable(&mut self)      -> (RequiredEvents, ClientResult);
  fn writable(&mut self)      -> (RequiredEvents, ClientResult);
  fn back_readable(&mut self) -> (RequiredEvents, ClientResult);
  fn back_writable(&mut self) -> (RequiredEvents, ClientResult);
  fn remove_backend(&mut self);
}

pub trait ProxyConfiguration<Server:Handler,Client> {
  fn connect_to_backend(&mut self, client:&mut Client) ->Result<TcpStream,ConnectionError>;
  fn notify(&mut self, event_loop: &mut EventLoop<Server>, message: ProxyOrder);
  fn accept(&mut self, token: Token) -> Option<(Client, bool)>;
}

pub struct Server<ServerConfiguration,Client> {
  configuration:   ServerConfiguration,
  clients:         Slab<Client>,
  backend:         Slab<ClientToken>,
  max_listeners:   usize,
  max_connections: usize,
  front_timeout:   u64,
  back_timeout:    u64,
}

impl<ServerConfiguration:ProxyConfiguration<Server<ServerConfiguration,Client>, Client>,Client:ProxyClient> Server<ServerConfiguration,Client> {
  pub fn new(max_listeners: usize, max_connections: usize, configuration: ServerConfiguration) -> Self {
    Server {
      configuration:   configuration,
      clients:         Slab::new_starting_at(Token(max_listeners), max_connections),
      backend:         Slab::new_starting_at(Token(max_listeners+max_connections), max_connections),
      max_listeners:   max_listeners,
      max_connections: max_connections,
      front_timeout:   DEFAULT_FRONT_TIMEOUT,
      back_timeout:    DEFAULT_BACK_TIMEOUT,
    }
  }

  pub fn configuration(&mut self) -> &mut ServerConfiguration {
    &mut self.configuration
  }

  pub fn close_client(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    self.clients[token].front_socket().shutdown(Shutdown::Both);
    event_loop.deregister(self.clients[token].front_socket());
    if let Some(sock) = self.clients[token].back_socket() {
      sock.shutdown(Shutdown::Both);
      event_loop.deregister(sock);
    }

    if let Some(backend_token) = self.clients[token].back_token() {
      if self.backend.contains(backend_token) {
        self.backend.remove(backend_token);
      }
    }
    self.clients.remove(token);
  }

  pub fn close_backend(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    if let Some(backend_token) = self.clients[token].back_token() {
      if self.backend.contains(backend_token) {
        self.backend.remove(backend_token);
        self.clients[token].remove_backend();
      }
    }
  }

  pub fn accept(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    if let Some((client, should_connect)) = self.configuration.accept(token) {
      if let Ok(client_token) = self.clients.insert(client) {
        event_loop.register(self.clients[client_token].front_socket(), client_token, EventSet::readable(), PollOpt::edge());
        &self.clients[client_token].set_front_token(client_token);
        if let Ok(timeout) = event_loop.timeout_ms(client_token.as_usize(), self.front_timeout) {
          &self.clients[client_token].set_front_timeout(timeout);
        }
        METRICS.lock().unwrap().gauge("accept", 1);
        if should_connect {
          self.connect_to_backend(event_loop, client_token);
        }
      } else {
        error!("could not add client to slab");
      }
    } else {
      error!("could not create a client");
    }
  }

  pub fn connect_to_backend(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
    match self.configuration.connect_to_backend(&mut self.clients[token]) {
      Ok(socket) => {
        if let Ok(backend_token) = self.backend.insert(token) {
          self.clients[token].set_back_socket(socket);
          self.clients[token].set_back_token(backend_token);

          if let Some(sock) = self.clients[token].back_socket() {
            event_loop.register(sock, backend_token, EventSet::writable(), PollOpt::edge());
          }
          if let Ok(timeout) = event_loop.timeout_ms(backend_token.as_usize(), self.back_timeout) {
            &self.clients[token].set_back_timeout(timeout);
          }
          return;
        }
      },
      Err(ConnectionError::HostNotFound) | Err(ConnectionError::NoBackendAvailable) => {
        let mut front_interest = EventSet::hup();
        front_interest.insert(EventSet::writable());
        let client = &self.clients[token];

        event_loop.reregister(client.front_socket(), token, front_interest, PollOpt::level() | PollOpt::oneshot());
      },
      _ => self.close_client(event_loop, token),
    }
  }

  pub fn get_client_token(&self, token: Token) -> Option<Token> {
    if token.as_usize() < self.max_listeners {
      None
    } else if token.as_usize() < self.max_listeners + self.max_connections && self.clients.contains(token) {
      Some(token)
    } else if token.as_usize() < self.max_listeners + 2 * self.max_connections && self.backend.contains(token) {
      if self.clients.contains(self.backend[token]) {
        Some(self.backend[token])
      } else {
        None
      }
    } else {
      None
    }
  }

  pub fn interpret_client_order(&mut self, event_loop: &mut EventLoop<Self>, token: Token, order: (RequiredEvents, ClientResult)) {
    //println!("ORDER: {:?}", order);
    match order.1 {
      ClientResult::CloseClient      => self.close_client(event_loop, token),
      ClientResult::CloseBackend     => self.close_backend(event_loop, token),
      ClientResult::CloseBothSuccess => self.close_client(event_loop, token),
      ClientResult::CloseBothFailure => self.close_client(event_loop, token),
      ClientResult::ConnectBackend   => {
        let mut front_interest = EventSet::hup();
        let mut back_interest  = EventSet::hup();
        front_interest.insert(EventSet::readable());
        back_interest.insert(EventSet::writable());
        self.reregister(event_loop, token, front_interest, back_interest);
        self.connect_to_backend(event_loop, token)
      },
      ClientResult::Continue         => {
        let mut front_interest = EventSet::hup();
        let mut back_interest  = EventSet::hup();
        if order.0.front_readable() {
          front_interest.insert(EventSet::readable());
        }
        if order.0.front_writable() {
          front_interest.insert(EventSet::writable());
        }
        if order.0.back_readable() {
          back_interest.insert(EventSet::readable());
        }
        if order.0.back_writable() {
          back_interest.insert(EventSet::writable());
        }
        self.reregister(event_loop, token, front_interest, back_interest)
      }
    }
  }

  fn reregister(&self, event_loop: &mut EventLoop<Self>, token: Token, front_interest: EventSet, back_interest: EventSet) {
    let client = &self.clients[token];

    if let Some(frontend_token) = client.front_token() {
      event_loop.reregister(client.front_socket(), frontend_token, front_interest, PollOpt::level() | PollOpt::oneshot());
    }
     if let Some(backend_token) = client.back_token() {
       if let Some(sock) = client.back_socket() {
         event_loop.reregister(sock, backend_token, back_interest, PollOpt::level() | PollOpt::oneshot());
       }
     }
  }
}

impl<ServerConfiguration:ProxyConfiguration<Server<ServerConfiguration,Client>, Client>,Client:ProxyClient> Handler for Server<ServerConfiguration,Client> {
  type Timeout = usize;
  type Message = ProxyOrder;

  fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
    trace!("{:?} got events: {:?}", token, events);
    if events.is_readable() {
      trace!("{:?} is readable", token);

      match socket_type(token, self.max_listeners, self.max_connections) {
        Some(SocketType::Listener) => {
          self.accept(event_loop, token)
        }

        Some(SocketType::FrontClient) => {
          if self.clients.contains(token) {
            let order = self.clients[token].readable();

            // FIXME: should clear the timeout only if data was consumed
            if let Some(timeout) = self.clients[token].front_timeout() {
              //println!("[{}] clearing timeout", token.as_usize());
              event_loop.clear_timeout(timeout);
            }
            if let Ok(timeout) = event_loop.timeout_ms(token.as_usize(), self.front_timeout) {
              //println!("[{}] resetting timeout", token.as_usize());
              &self.clients[token].set_front_timeout(timeout);
            }

            self.interpret_client_order(event_loop, token, order);
          } else {
            info!("client {:?} was removed", token);
          }
        }

        Some(SocketType::BackClient) => {
          if let Some(tok) = self.get_client_token(token) {
            let order = self.clients[tok].back_readable();

            // FIXME: should clear the timeout only if data was consumed
            if let Some(timeout) = self.clients[tok].back_timeout() {
              //println!("[{}] clearing timeout", token.as_usize());
              event_loop.clear_timeout(timeout);
            }
            if let Ok(timeout) = event_loop.timeout_ms(token.as_usize(), self.back_timeout) {
              //println!("[{}] resetting timeout", token.as_usize());
              &self.clients[tok].set_back_timeout(timeout);
            }

            self.interpret_client_order(event_loop, tok, order);
          }
        }

        None => {}
      }
    }

    if events.is_writable() {
      trace!("{:?} is writable", token);

      match socket_type(token, self.max_listeners, self.max_connections) {
        Some(SocketType::Listener) => {
          error!("received writable for listener {:?}, this should not happen", token);
        }

        Some(SocketType::FrontClient) => {
          if self.clients.contains(token) {
            let order = self.clients[token].writable();
            trace!("interpreting client order {:?}", order);
            self.interpret_client_order(event_loop, token, order);
          } else {
            info!("client {:?} was removed", token);
          }
        }

        Some(SocketType::BackClient) => {
          if let Some(tok) = self.get_client_token(token) {
            let order = self.clients[tok].back_writable();
            self.interpret_client_order(event_loop, tok, order);
          }
        }

        None => {}
      }
    }

    if events.is_hup() {
      match socket_type(token, self.max_listeners, self.max_connections) {
        Some(SocketType::Listener) => {
          error!("should not happen: server {:?} closed", token);
        }

        Some(SocketType::FrontClient) => {
          if self.clients.contains(token) {
            if self.clients[token].front_hup() == ClientResult::CloseClient {
              self.close_client(event_loop, token);
            }
          } else {
            info!("client {:?} was removed", token);
          }
        }

        Some(SocketType::BackClient) => {
          if let Some(tok) = self.get_client_token(token) {
            if self.clients[tok].front_hup() == ClientResult::CloseClient {
              self.close_client(event_loop, tok);
            }
          }
        }

        None => {}
      }
    }
  }

  fn notify(&mut self, event_loop: &mut EventLoop<Self>, message: Self::Message) {
    self.configuration.notify(event_loop, message);
  }

  fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
    let token = Token(timeout);
    match socket_type(token, self.max_listeners, self.max_connections) {
      Some(SocketType::Listener) => {
        error!("the listener socket should have no timeout set");
      },
      Some(SocketType::FrontClient) => {
        if self.clients.contains(token) {
          debug!("frontend [{}] got timeout, closing", timeout);
          self.close_client(event_loop, token);
        }
      },
      Some(SocketType::BackClient) => {
        if let Some(tok) = self.get_client_token(token) {
          debug!("backend [{}] got timeout, closing", timeout);
          self.close_client(event_loop, tok);
        }
      }
      None => {}
    }
  }

  fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
    warn!("interrupted");
  }
}

<|endoftext|>


<commit_before>//! Cookie session.
//!
//! [**CookieSession**](struct.CookieSession.html)
//! uses cookies as session storage. `CookieSession` creates sessions
//! which are limited to storing fewer than 4000 bytes of data, as the payload
//! must fit into a single cookie. An internal server error is generated if a
//! session contains more than 4000 bytes.
//!
//! A cookie may have a security policy of *signed* or *private*. Each has
//! a respective `CookieSession` constructor.
//!
//! A *signed* cookie may be viewed but not modified by the client. A *private*
//! cookie may neither be viewed nor modified by the client.
//!
//! The constructors take a key as an argument. This is the private key
//! for cookie session - when this value is changed, all session data is lost.

use std::collections::HashMap;
use std::rc::Rc;

use actix_service::{Service, Transform};
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::http::{header::SET_COOKIE, HeaderValue};
use actix_web::{Error, HttpMessage, ResponseError};
use derive_more::{Display, From};
use futures::future::{ok, Future, FutureResult};
use futures::Poll;
use serde_json::error::Error as JsonError;
use time::Duration;

use crate::Session;

/// Errors that can occur during handling cookie session
#[derive(Debug, From, Display)]
pub enum CookieSessionError {
    /// Size of the serialized session is greater than 4000 bytes.
    #[display(fmt = "Size of the serialized session is greater than 4000 bytes.")]
    Overflow,
    /// Fail to serialize session.
    #[display(fmt = "Fail to serialize session")]
    Serialize(JsonError),
}

impl ResponseError for CookieSessionError {}

enum CookieSecurity {
    Signed,
    Private,
}

struct CookieSessionInner {
    key: Key,
    security: CookieSecurity,
    name: String,
    path: String,
    domain: Option<String>,
    secure: bool,
    http_only: bool,
    max_age: Option<Duration>,
    same_site: Option<SameSite>,
}

impl CookieSessionInner {
    fn new(key: &[u8], security: CookieSecurity) -> CookieSessionInner {
        CookieSessionInner {
            security,
            key: Key::from_master(key),
            name: "actix-session".to_owned(),
            path: "/".to_owned(),
            domain: None,
            secure: true,
            http_only: true,
            max_age: None,
            same_site: None,
        }
    }

    fn set_cookie<B>(
        &self,
        res: &mut ServiceResponse<B>,
        state: impl Iterator<Item = (String, String)>,
    ) -> Result<(), Error> {
        let state: HashMap<String, String> = state.collect();
        let value =
            serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
        if value.len() > 4064 {
            return Err(CookieSessionError::Overflow.into());
        }

        let mut cookie = Cookie::new(self.name.clone(), value);
        cookie.set_path(self.path.clone());
        cookie.set_secure(self.secure);
        cookie.set_http_only(self.http_only);

        if let Some(ref domain) = self.domain {
            cookie.set_domain(domain.clone());
        }

        if let Some(max_age) = self.max_age {
            cookie.set_max_age(max_age);
        }

        if let Some(same_site) = self.same_site {
            cookie.set_same_site(same_site);
        }

        let mut jar = CookieJar::new();

        match self.security {
            CookieSecurity::Signed => jar.signed(&self.key).add(cookie),
            CookieSecurity::Private => jar.private(&self.key).add(cookie),
        }

        for cookie in jar.delta() {
            let val = HeaderValue::from_str(&cookie.encoded().to_string())?;
            res.headers_mut().append(SET_COOKIE, val);
        }

        Ok(())
    }

    fn load(&self, req: &ServiceRequest) -> HashMap<String, String> {
        if let Ok(cookies) = req.cookies() {
            for cookie in cookies.iter() {
                if cookie.name() == self.name {
                    let mut jar = CookieJar::new();
                    jar.add_original(cookie.clone());

                    let cookie_opt = match self.security {
                        CookieSecurity::Signed => jar.signed(&self.key).get(&self.name),
                        CookieSecurity::Private => {
                            jar.private(&self.key).get(&self.name)
                        }
                    };
                    if let Some(cookie) = cookie_opt {
                        if let Ok(val) = serde_json::from_str(cookie.value()) {
                            return val;
                        }
                    }
                }
            }
        }
        HashMap::new()
    }
}

/// Use cookies for session storage.
///
/// `CookieSession` creates sessions which are limited to storing
/// fewer than 4000 bytes of data (as the payload must fit into a single
/// cookie). An Internal Server Error is generated if the session contains more
/// than 4000 bytes.
///
/// A cookie may have a security policy of *signed* or *private*. Each has a
/// respective `CookieSessionBackend` constructor.
///
/// A *signed* cookie is stored on the client as plaintext alongside
/// a signature such that the cookie may be viewed but not modified by the
/// client.
///
/// A *private* cookie is stored on the client as encrypted text
/// such that it may neither be viewed nor modified by the client.
///
/// The constructors take a key as an argument.
/// This is the private key for cookie session - when this value is changed,
/// all session data is lost. The constructors will panic if the key is less
/// than 32 bytes in length.
///
/// The backend relies on `cookie` crate to create and read cookies.
/// By default all cookies are percent encoded, but certain symbols may
/// cause troubles when reading cookie, if they are not properly percent encoded.
///
/// # Example
///
/// ```rust
/// use actix_session::CookieSession;
/// use actix_web::{web, App, HttpResponse, HttpServer};
///
/// fn main() {
///     let app = App::new().wrap(
///         CookieSession::signed(&[0; 32])
///             .domain("www.rust-lang.org")
///             .name("actix_session")
///             .path("/")
///             .secure(true))
///         .service(web::resource("/").to(|| HttpResponse::Ok()));
/// }
/// ```
pub struct CookieSession(Rc<CookieSessionInner>);

impl CookieSession {
    /// Construct new *signed* `CookieSessionBackend` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn signed(key: &[u8]) -> CookieSession {
        CookieSession(Rc::new(CookieSessionInner::new(
            key,
            CookieSecurity::Signed,
        )))
    }

    /// Construct new *private* `CookieSessionBackend` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn private(key: &[u8]) -> CookieSession {
        CookieSession(Rc::new(CookieSessionInner::new(
            key,
            CookieSecurity::Private,
        )))
    }

    /// Sets the `path` field in the session cookie being built.
    pub fn path<S: Into<String>>(mut self, value: S) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().path = value.into();
        self
    }

    /// Sets the `name` field in the session cookie being built.
    pub fn name<S: Into<String>>(mut self, value: S) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().name = value.into();
        self
    }

    /// Sets the `domain` field in the session cookie being built.
    pub fn domain<S: Into<String>>(mut self, value: S) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().domain = Some(value.into());
        self
    }

    /// Sets the `secure` field in the session cookie being built.
    ///
    /// If the `secure` field is set, a cookie will only be transmitted when the
    /// connection is secure - i.e. `https`
    pub fn secure(mut self, value: bool) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().secure = value;
        self
    }

    /// Sets the `http_only` field in the session cookie being built.
    pub fn http_only(mut self, value: bool) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().http_only = value;
        self
    }

    /// Sets the `same_site` field in the session cookie being built.
    pub fn same_site(mut self, value: SameSite) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().same_site = Some(value);
        self
    }

    /// Sets the `max-age` field in the session cookie being built.
    pub fn max_age(mut self, value: Duration) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
        self
    }
}

impl<S, B: 'static> Transform<S> for CookieSession
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>>,
    S::Future: 'static,
    S::Error: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type InitError = ();
    type Transform = CookieSessionMiddleware<S>;
    type Future = FutureResult<Self::Transform, Self::InitError>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(CookieSessionMiddleware {
            service,
            inner: self.0.clone(),
        })
    }
}

/// Cookie session middleware
pub struct CookieSessionMiddleware<S> {
    service: S,
    inner: Rc<CookieSessionInner>,
}

impl<S, B: 'static> Service for CookieSessionMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>>,
    S::Future: 'static,
    S::Error: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.service.poll_ready()
    }

    fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
        let inner = self.inner.clone();
        let state = self.inner.load(&req);
        Session::set_session(state.into_iter(), &mut req);

        Box::new(self.service.call(req).map(move |mut res| {
            if let Some(state) = Session::get_changes(&mut res) {
                res.checked_expr(|res| inner.set_cookie(res, state))
            } else {
                res
            }
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use actix_web::{test, web, App};

    #[test]
    fn cookie_session() {
        let mut app = test::init_service(
            App::new()
                .wrap(CookieSession::signed(&[0; 32]).secure(false))
                .service(web::resource("/").to(|ses: Session| {
                    let _ = ses.set("counter", 100);
                    "test"
                })),
        );

        let request = test::TestRequest::get().to_request();
        let response = test::block_on(app.call(request)).unwrap();
        assert!(response
            .response()
            .cookies()
            .find(|c| c.name() == "actix-session")
            .is_some());
    }

    #[test]
    fn cookie_session_extractor() {
        let mut app = test::init_service(
            App::new()
                .wrap(CookieSession::signed(&[0; 32]).secure(false))
                .service(web::resource("/").to(|ses: Session| {
                    let _ = ses.set("counter", 100);
                    "test"
                })),
        );

        let request = test::TestRequest::get().to_request();
        let response = test::block_on(app.call(request)).unwrap();
        assert!(response
            .response()
            .cookies()
            .find(|c| c.name() == "actix-session")
            .is_some());
    }
}
<commit_msg>add cookie session test<commit_after>//! Cookie session.
//!
//! [**CookieSession**](struct.CookieSession.html)
//! uses cookies as session storage. `CookieSession` creates sessions
//! which are limited to storing fewer than 4000 bytes of data, as the payload
//! must fit into a single cookie. An internal server error is generated if a
//! session contains more than 4000 bytes.
//!
//! A cookie may have a security policy of *signed* or *private*. Each has
//! a respective `CookieSession` constructor.
//!
//! A *signed* cookie may be viewed but not modified by the client. A *private*
//! cookie may neither be viewed nor modified by the client.
//!
//! The constructors take a key as an argument. This is the private key
//! for cookie session - when this value is changed, all session data is lost.

use std::collections::HashMap;
use std::rc::Rc;
use std::time::Duration;

use actix_service::{Service, Transform};
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::http::{header::SET_COOKIE, HeaderValue};
use actix_web::{Error, HttpMessage, ResponseError};
use derive_more::{Display, From};
use futures::future::{ok, Future, FutureResult};
use futures::Poll;
use serde_json::error::Error as JsonError;

use crate::Session;

/// Errors that can occur during handling cookie session
#[derive(Debug, From, Display)]
pub enum CookieSessionError {
    /// Size of the serialized session is greater than 4000 bytes.
    #[display(fmt = "Size of the serialized session is greater than 4000 bytes.")]
    Overflow,
    /// Fail to serialize session.
    #[display(fmt = "Fail to serialize session")]
    Serialize(JsonError),
}

impl ResponseError for CookieSessionError {}

enum CookieSecurity {
    Signed,
    Private,
}

struct CookieSessionInner {
    key: Key,
    security: CookieSecurity,
    name: String,
    path: String,
    domain: Option<String>,
    secure: bool,
    http_only: bool,
    max_age: Option<Duration>,
    same_site: Option<SameSite>,
}

impl CookieSessionInner {
    fn new(key: &[u8], security: CookieSecurity) -> CookieSessionInner {
        CookieSessionInner {
            security,
            key: Key::from_master(key),
            name: "actix-session".to_owned(),
            path: "/".to_owned(),
            domain: None,
            secure: true,
            http_only: true,
            max_age: None,
            same_site: None,
        }
    }

    fn set_cookie<B>(
        &self,
        res: &mut ServiceResponse<B>,
        state: impl Iterator<Item = (String, String)>,
    ) -> Result<(), Error> {
        let state: HashMap<String, String> = state.collect();
        let value =
            serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
        if value.len() > 4064 {
            return Err(CookieSessionError::Overflow.into());
        }

        let mut cookie = Cookie::new(self.name.clone(), value);
        cookie.set_path(self.path.clone());
        cookie.set_secure(self.secure);
        cookie.set_http_only(self.http_only);

        if let Some(ref domain) = self.domain {
            cookie.set_domain(domain.clone());
        }

        if let Some(max_age) = self.max_age {
            cookie.set_max_age(time::Duration::from_std(max_age).unwrap());
        }

        if let Some(same_site) = self.same_site {
            cookie.set_same_site(same_site);
        }

        let mut jar = CookieJar::new();

        match self.security {
            CookieSecurity::Signed => jar.signed(&self.key).add(cookie),
            CookieSecurity::Private => jar.private(&self.key).add(cookie),
        }

        for cookie in jar.delta() {
            let val = HeaderValue::from_str(&cookie.encoded().to_string())?;
            res.headers_mut().append(SET_COOKIE, val);
        }

        Ok(())
    }

    fn load(&self, req: &ServiceRequest) -> HashMap<String, String> {
        if let Ok(cookies) = req.cookies() {
            for cookie in cookies.iter() {
                if cookie.name() == self.name {
                    let mut jar = CookieJar::new();
                    jar.add_original(cookie.clone());

                    let cookie_opt = match self.security {
                        CookieSecurity::Signed => jar.signed(&self.key).get(&self.name),
                        CookieSecurity::Private => {
                            jar.private(&self.key).get(&self.name)
                        }
                    };
                    if let Some(cookie) = cookie_opt {
                        if let Ok(val) = serde_json::from_str(cookie.value()) {
                            return val;
                        }
                    }
                }
            }
        }
        HashMap::new()
    }
}

/// Use cookies for session storage.
///
/// `CookieSession` creates sessions which are limited to storing
/// fewer than 4000 bytes of data (as the payload must fit into a single
/// cookie). An Internal Server Error is generated if the session contains more
/// than 4000 bytes.
///
/// A cookie may have a security policy of *signed* or *private*. Each has a
/// respective `CookieSessionBackend` constructor.
///
/// A *signed* cookie is stored on the client as plaintext alongside
/// a signature such that the cookie may be viewed but not modified by the
/// client.
///
/// A *private* cookie is stored on the client as encrypted text
/// such that it may neither be viewed nor modified by the client.
///
/// The constructors take a key as an argument.
/// This is the private key for cookie session - when this value is changed,
/// all session data is lost. The constructors will panic if the key is less
/// than 32 bytes in length.
///
/// The backend relies on `cookie` crate to create and read cookies.
/// By default all cookies are percent encoded, but certain symbols may
/// cause troubles when reading cookie, if they are not properly percent encoded.
///
/// # Example
///
/// ```rust
/// use actix_session::CookieSession;
/// use actix_web::{web, App, HttpResponse, HttpServer};
///
/// fn main() {
///     let app = App::new().wrap(
///         CookieSession::signed(&[0; 32])
///             .domain("www.rust-lang.org")
///             .name("actix_session")
///             .path("/")
///             .secure(true))
///         .service(web::resource("/").to(|| HttpResponse::Ok()));
/// }
/// ```
pub struct CookieSession(Rc<CookieSessionInner>);

impl CookieSession {
    /// Construct new *signed* `CookieSessionBackend` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn signed(key: &[u8]) -> CookieSession {
        CookieSession(Rc::new(CookieSessionInner::new(
            key,
            CookieSecurity::Signed,
        )))
    }

    /// Construct new *private* `CookieSessionBackend` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn private(key: &[u8]) -> CookieSession {
        CookieSession(Rc::new(CookieSessionInner::new(
            key,
            CookieSecurity::Private,
        )))
    }

    /// Sets the `path` field in the session cookie being built.
    pub fn path<S: Into<String>>(mut self, value: S) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().path = value.into();
        self
    }

    /// Sets the `name` field in the session cookie being built.
    pub fn name<S: Into<String>>(mut self, value: S) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().name = value.into();
        self
    }

    /// Sets the `domain` field in the session cookie being built.
    pub fn domain<S: Into<String>>(mut self, value: S) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().domain = Some(value.into());
        self
    }

    /// Sets the `secure` field in the session cookie being built.
    ///
    /// If the `secure` field is set, a cookie will only be transmitted when the
    /// connection is secure - i.e. `https`
    pub fn secure(mut self, value: bool) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().secure = value;
        self
    }

    /// Sets the `http_only` field in the session cookie being built.
    pub fn http_only(mut self, value: bool) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().http_only = value;
        self
    }

    /// Sets the `same_site` field in the session cookie being built.
    pub fn same_site(mut self, value: SameSite) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().same_site = Some(value);
        self
    }

    /// Sets the `max-age` field in the session cookie being built.
    pub fn max_age(mut self, value: Duration) -> CookieSession {
        Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
        self
    }
}

impl<S, B: 'static> Transform<S> for CookieSession
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>>,
    S::Future: 'static,
    S::Error: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type InitError = ();
    type Transform = CookieSessionMiddleware<S>;
    type Future = FutureResult<Self::Transform, Self::InitError>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(CookieSessionMiddleware {
            service,
            inner: self.0.clone(),
        })
    }
}

/// Cookie session middleware
pub struct CookieSessionMiddleware<S> {
    service: S,
    inner: Rc<CookieSessionInner>,
}

impl<S, B: 'static> Service for CookieSessionMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>>,
    S::Future: 'static,
    S::Error: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.service.poll_ready()
    }

    fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
        let inner = self.inner.clone();
        let state = self.inner.load(&req);
        Session::set_session(state.into_iter(), &mut req);

        Box::new(self.service.call(req).map(move |mut res| {
            if let Some(state) = Session::get_changes(&mut res) {
                res.checked_expr(|res| inner.set_cookie(res, state))
            } else {
                res
            }
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use actix_web::{test, web, App};
    use bytes::Bytes;

    #[test]
    fn cookie_session() {
        let mut app = test::init_service(
            App::new()
                .wrap(CookieSession::signed(&[0; 32]).secure(false))
                .service(web::resource("/").to(|ses: Session| {
                    let _ = ses.set("counter", 100);
                    "test"
                })),
        );

        let request = test::TestRequest::get().to_request();
        let response = test::block_on(app.call(request)).unwrap();
        assert!(response
            .response()
            .cookies()
            .find(|c| c.name() == "actix-session")
            .is_some());
    }

    #[test]
    fn private_cookie() {
        let mut app = test::init_service(
            App::new()
                .wrap(CookieSession::private(&[0; 32]).secure(false))
                .service(web::resource("/").to(|ses: Session| {
                    let _ = ses.set("counter", 100);
                    "test"
                })),
        );

        let request = test::TestRequest::get().to_request();
        let response = test::block_on(app.call(request)).unwrap();
        assert!(response
            .response()
            .cookies()
            .find(|c| c.name() == "actix-session")
            .is_some());
    }

    #[test]
    fn cookie_session_extractor() {
        let mut app = test::init_service(
            App::new()
                .wrap(CookieSession::signed(&[0; 32]).secure(false))
                .service(web::resource("/").to(|ses: Session| {
                    let _ = ses.set("counter", 100);
                    "test"
                })),
        );

        let request = test::TestRequest::get().to_request();
        let response = test::block_on(app.call(request)).unwrap();
        assert!(response
            .response()
            .cookies()
            .find(|c| c.name() == "actix-session")
            .is_some());
    }

    #[test]
    fn basics() {
        let mut app = test::init_service(
            App::new()
                .wrap(
                    CookieSession::signed(&[0; 32])
                        .path("/test/")
                        .name("actix-test")
                        .domain("localhost")
                        .http_only(true)
                        .same_site(SameSite::Lax)
                        .max_age(Duration::from_secs(100)),
                )
                .service(web::resource("/").to(|ses: Session| {
                    let _ = ses.set("counter", 100);
                    "test"
                }))
                .service(web::resource("/test/").to(|ses: Session| {
                    let val: usize = ses.get("counter").unwrap().unwrap();
                    format!("counter: {}", val)
                })),
        );

        let request = test::TestRequest::get().to_request();
        let response = test::block_on(app.call(request)).unwrap();
        let cookie = response
            .response()
            .cookies()
            .find(|c| c.name() == "actix-test")
            .unwrap()
            .clone();
        assert_eq!(cookie.path().unwrap(), "/test/");

        let request = test::TestRequest::with_uri("/test/")
            .cookie(cookie)
            .to_request();
        let body = test::read_response(&mut app, request);
        assert_eq!(body, Bytes::from_static(b"counter: 100"));
    }
}
<|endoftext|>


<commit_before>use std::option::Option;
use std::marker::PhantomData;

pub trait Param {
    type Param;
}

pub trait ReParam<B>: Param {
    type Output: Param<Param=B>;
}

impl<'a, A: Param> Param for &'a A {
    type Param = A::Param;
}

impl<'a, A: Param> Param for &'a mut A {
    type Param = A::Param;
}

impl<A> Param for Option<A> {
    type Param = A;
}

impl<A, B> ReParam<B> for Option<A> {
    type Output = Option<B>;
}

impl<X, A> Param for (X, A) {
    type Param = A;
}

impl<X, A, B> ReParam<B> for (X, A) {
    type Output = (X, B);
}

impl<A> Param for PhantomData<A> {
    type Param = A;
}

impl<A, B> ReParam<B> for PhantomData<A> {
    type Output = PhantomData<B>;
}
<commit_msg>make Box and Result parametric<commit_after>use std::option::Option;
use std::marker::PhantomData;

pub trait Param {
    type Param;
}

pub trait ReParam<B>: Param {
    type Output: Param<Param=B>;
}

impl<'a, A: Param> Param for &'a A {
    type Param = A::Param;
}

impl<'a, A: Param> Param for &'a mut A {
    type Param = A::Param;
}

impl<A> Param for Option<A> {
    type Param = A;
}

impl<A, B> ReParam<B> for Option<A> {
    type Output = Option<B>;
}

impl<X, A> Param for (X, A) {
    type Param = A;
}

impl<X, A, B> ReParam<B> for (X, A) {
    type Output = (X, B);
}

impl<A> Param for PhantomData<A> {
    type Param = A;
}

impl<A, B> ReParam<B> for PhantomData<A> {
    type Output = PhantomData<B>;
}

impl<A> Param for Box<A> {
    type Param = A;
}

impl<A, B> ReParam<B> for Box<A> {
    type Output = Box<B>;
}

impl<A, E> Param for Result<A, E> {
    type Param = A;
}

impl<A, B, E> ReParam<B> for Result<A, E> {
    type Output = Result<B, E>;
}
<|endoftext|>


<commit_before>// Discord Dependencies -------------------------------------------------------
use discord::model::ChannelId;

// Internal Dependencies ------------------------------------------------------
use ::audio::MixerCommand;
use ::bot::BotConfig;
use ::core::EventQueue;
use ::effect::Effect;
use super::Server;

// Server Effect Interface ----------------------------------------------------
impl Server {

    pub fn play_effects(
        &mut self,
        channel_id: &ChannelId,
        effects: &[Effect],
        queued: bool,
        queue: &mut EventQueue
    ) {

        let has_channel = if let Some(channel) = self.channels.get(channel_id) {

            // When pinned, only play effects for the pinned channel
            if let Some(pinned_channel_id) = self.pinned_channel_id {
                if *channel_id == pinned_channel_id {
                    info!("{} {} playing {} effect(s)...", self, channel, effects.len());
                    true

                } else {
                    info!("{} {} not playing effect(s), pinned to another channel.", self, channel);
                    false
                }

            } else {
                info!("{} {} playing {} effect(s)...", self, channel, effects.len());
                true
            }

        } else {
            false
        };

        if has_channel {

            // See if we're actually in the requested channel or if we're going
            // to switch there.
            //
            // We want to prevent playing greetings from other channels in case
            // we are pinned to another channel already.
            if self.join_voice(channel_id, queue) {
                if let Some(queue) = self.mixer_queue.as_mut() {
                    if queued {
                        queue.send(MixerCommand::QueueEffects(effects.to_vec())).ok();

                    } else {
                        queue.send(MixerCommand::PlayEffects(effects.to_vec())).ok();
                    }
                }
            }

        }

    }

    pub fn silence_active_effects(&mut self) {
        if let Some(queue) = self.mixer_queue.as_mut() {
            queue.send(MixerCommand::ClearQueue).ok();
        }
    }

    pub fn has_effect(&self, effect_name: &str) -> bool {
        self.effects.has_effect(effect_name)
    }

    pub fn get_effect(&self, effect_name: &str) -> Option<&Effect> {
        self.effects.get_effect(effect_name)
    }

    pub fn has_matching_effects(&self, effect_name: &str, bot_config: &BotConfig) -> bool {
        !self.map_effects(
            &[effect_name.to_string()],
            true,
            bot_config

        ).is_empty()
    }

    pub fn map_effects(
        &self,
        patterns: &[String],
        match_all: bool,
        bot_config: &BotConfig

    ) -> Vec<&Effect> {
        self.effects.map_patterns(
            patterns,
            Some(&self.config.aliases),
            match_all,
            bot_config
        )
    }

    pub fn map_similiar_effects(&self, patterns: &[String]) -> Vec<&str> {
        self.effects.map_similiar(
            patterns,
            &self.config.aliases
        )
    }

    pub fn rename_effect(&mut self, effect: &Effect, effect_name: &str) -> Result<(), String> {
        self.effects.rename_effect(&self.config, effect, effect_name)
    }

    pub fn delete_effect(&mut self, effect: &Effect) -> Result<(), String> {
        self.effects.delete_effect(&self.config, effect)
    }

    pub fn download_effect(
        &mut self,
        effect_name: &str,
        upload_url: &str,
        uploader: &str

    ) -> Result<(), String> {
        self.effects.download_effect(
            &self.config,
            effect_name,
            upload_url,
            uploader
        )
    }

    pub fn download_transcript(
        &mut self,
        effect_name: &str,
        upload_url: &str

    ) -> Result<(), String> {
        self.effects.download_transcript(
            &self.config,
            effect_name,
            upload_url
        )
    }

}

<commit_msg>Minor clippy cleanup.<commit_after>// Discord Dependencies -------------------------------------------------------
use discord::model::ChannelId;

// Internal Dependencies ------------------------------------------------------
use ::audio::MixerCommand;
use ::bot::BotConfig;
use ::core::EventQueue;
use ::effect::Effect;
use super::Server;

// Server Effect Interface ----------------------------------------------------
impl Server {

    pub fn play_effects(
        &mut self,
        channel_id: &ChannelId,
        effects: &[Effect],
        queued: bool,
        queue: &mut EventQueue
    ) {

        let has_channel = if let Some(channel) = self.channels.get(channel_id) {

            // When pinned, only play effects for the pinned channel
            if let Some(pinned_channel_id) = self.pinned_channel_id {
                if *channel_id == pinned_channel_id {
                    info!("{} {} playing {} effect(s)...", self, channel, effects.len());
                    true

                } else {
                    info!("{} {} not playing effect(s), pinned to another channel.", self, channel);
                    false
                }

            } else {
                info!("{} {} playing {} effect(s)...", self, channel, effects.len());
                true
            }

        } else {
            false
        };

        // See if we're actually in the requested channel or if we're going
        // to switch there.
        //
        // We want to prevent playing greetings from other channels in case
        // we are pinned to another channel already.
        if has_channel && self.join_voice(channel_id, queue) {
            if let Some(queue) = self.mixer_queue.as_mut() {
                if queued {
                    queue.send(MixerCommand::QueueEffects(effects.to_vec())).ok();

                } else {
                    queue.send(MixerCommand::PlayEffects(effects.to_vec())).ok();
                }
            }
        }

    }

    pub fn silence_active_effects(&mut self) {
        if let Some(queue) = self.mixer_queue.as_mut() {
            queue.send(MixerCommand::ClearQueue).ok();
        }
    }

    pub fn has_effect(&self, effect_name: &str) -> bool {
        self.effects.has_effect(effect_name)
    }

    pub fn get_effect(&self, effect_name: &str) -> Option<&Effect> {
        self.effects.get_effect(effect_name)
    }

    pub fn has_matching_effects(&self, effect_name: &str, bot_config: &BotConfig) -> bool {
        !self.map_effects(
            &[effect_name.to_string()],
            true,
            bot_config

        ).is_empty()
    }

    pub fn map_effects(
        &self,
        patterns: &[String],
        match_all: bool,
        bot_config: &BotConfig

    ) -> Vec<&Effect> {
        self.effects.map_patterns(
            patterns,
            Some(&self.config.aliases),
            match_all,
            bot_config
        )
    }

    pub fn map_similiar_effects(&self, patterns: &[String]) -> Vec<&str> {
        self.effects.map_similiar(
            patterns,
            &self.config.aliases
        )
    }

    pub fn rename_effect(&mut self, effect: &Effect, effect_name: &str) -> Result<(), String> {
        self.effects.rename_effect(&self.config, effect, effect_name)
    }

    pub fn delete_effect(&mut self, effect: &Effect) -> Result<(), String> {
        self.effects.delete_effect(&self.config, effect)
    }

    pub fn download_effect(
        &mut self,
        effect_name: &str,
        upload_url: &str,
        uploader: &str

    ) -> Result<(), String> {
        self.effects.download_effect(
            &self.config,
            effect_name,
            upload_url,
            uploader
        )
    }

    pub fn download_transcript(
        &mut self,
        effect_name: &str,
        upload_url: &str

    ) -> Result<(), String> {
        self.effects.download_transcript(
            &self.config,
            effect_name,
            upload_url
        )
    }

}

<|endoftext|>


<commit_before>use crate::argv::*;
use std::env;
use std::path::Path;

#[test]
fn no_option() {
    match parse_options(&["git-brws"]).unwrap() {
        ParsedArgv::Parsed(o) => {
            println!("FOO! {:?}", o);
            assert!(vec![
                "https://github.com/rhysd/git-brws.git",
                "ssh://git@github.com:22/rhysd/git-brws.git",
                "git@github.com:rhysd/git-brws.git",
            ]
            .iter()
            .any(|u| o.repo == u.to_string()));
            assert_eq!(o.branch, None);
            assert!(o.git_dir.ends_with(".git"));
            assert!(o.args.is_empty());
            assert!(!o.stdout);
        }
        r => assert!(false, "Failed to parse args with no option: {:?}", r),
    };

    match parse_options(&["git-brws", "foo", "bar"]).unwrap() {
        ParsedArgv::Parsed(o) => {
            assert_eq!(o.args.len(), 2);
        }
        _ => assert!(false),
    };
}

#[test]
fn with_options() {
    match parse_options(&[
        "git-brws", "foo", "-u", "-r", "foo/bar", "--dir", ".", "bar", "-b", "dev",
    ])
    .unwrap()
    {
        ParsedArgv::Parsed(o) => {
            assert_eq!(o.repo, "https://github.com/foo/bar.git");
            assert_eq!(o.branch, Some("dev".to_string()));
            assert!(o.git_dir.ends_with(".git"));
            assert_eq!(o.args.len(), 2);
            assert!(o.stdout);
        }
        _ => assert!(false),
    };
}

#[test]
fn ssh_conversion_with_option() {
    match parse_options(&["git-brws", "-r", "git@github.com:user/repo.git"]).unwrap() {
        ParsedArgv::Parsed(o) => {
            assert_eq!(o.repo, "ssh://git@github.com:22/user/repo.git");
        }
        p => assert!(
            false,
            "Parse must be succeeded but actually results in {:?}",
            p
        ),
    };
}

#[test]
fn repo_formatting() {
    let p = |r| parse_options(&["git-brws", "-r", r]).unwrap();
    match p("bitbucket.org/foo/bar") {
        ParsedArgv::Parsed(o) => assert_eq!(o.repo, "https://bitbucket.org/foo/bar.git"),
        _ => assert!(false),
    }
    match p("https://gitlab.com/foo/bar") {
        ParsedArgv::Parsed(o) => assert_eq!(o.repo, "https://gitlab.com/foo/bar.git"),
        _ => assert!(false),
    }
}

#[test]
fn help_option() {
    match parse_options(&["git-brws", "-h"]).unwrap() {
        ParsedArgv::Help(s) => {
            assert!(s.starts_with("Usage:"));
        }
        _ => assert!(false),
    }
}

#[test]
fn version_option() {
    match parse_options(&["git-brws", "-v"]).unwrap() {
        ParsedArgv::Version(s) => {
            assert!(!s.is_empty());
        }
        _ => assert!(false),
    }
}

#[test]
fn unknown_options() {
    assert!(parse_options(&["git-brws", "--unknown"]).is_err());
}

#[test]
fn detect_git_dir() {
    let current = env::current_dir().unwrap();
    let mut p = current.clone();
    p.push(Path::new("src/test/"));
    match parse_options(&["git-brws", "-d", p.to_str().unwrap()]).unwrap() {
        ParsedArgv::Parsed(o) => {
            let mut expected = current.clone();
            expected.push(".git");
            assert_eq!(o.git_dir, expected);
        }
        _ => assert!(false),
    }
}
<commit_msg>fix test which failed on Windows<commit_after>use crate::argv::*;
use std::env;
use std::fs;

#[test]
fn no_option() {
    match parse_options(&["git-brws"]).unwrap() {
        ParsedArgv::Parsed(o) => {
            println!("FOO! {:?}", o);
            assert!(vec![
                "https://github.com/rhysd/git-brws.git",
                "ssh://git@github.com:22/rhysd/git-brws.git",
                "git@github.com:rhysd/git-brws.git",
            ]
            .iter()
            .any(|u| o.repo == u.to_string()));
            assert_eq!(o.branch, None);
            assert!(o.git_dir.ends_with(".git"));
            assert!(o.args.is_empty());
            assert!(!o.stdout);
        }
        r => assert!(false, "Failed to parse args with no option: {:?}", r),
    };

    match parse_options(&["git-brws", "foo", "bar"]).unwrap() {
        ParsedArgv::Parsed(o) => {
            assert_eq!(o.args.len(), 2);
        }
        _ => assert!(false),
    };
}

#[test]
fn with_options() {
    match parse_options(&[
        "git-brws", "foo", "-u", "-r", "foo/bar", "--dir", ".", "bar", "-b", "dev",
    ])
    .unwrap()
    {
        ParsedArgv::Parsed(o) => {
            assert_eq!(o.repo, "https://github.com/foo/bar.git");
            assert_eq!(o.branch, Some("dev".to_string()));
            assert!(o.git_dir.ends_with(".git"));
            assert_eq!(o.args.len(), 2);
            assert!(o.stdout);
        }
        _ => assert!(false),
    };
}

#[test]
fn ssh_conversion_with_option() {
    match parse_options(&["git-brws", "-r", "git@github.com:user/repo.git"]).unwrap() {
        ParsedArgv::Parsed(o) => {
            assert_eq!(o.repo, "ssh://git@github.com:22/user/repo.git");
        }
        p => assert!(
            false,
            "Parse must be succeeded but actually results in {:?}",
            p
        ),
    };
}

#[test]
fn repo_formatting() {
    let p = |r| parse_options(&["git-brws", "-r", r]).unwrap();
    match p("bitbucket.org/foo/bar") {
        ParsedArgv::Parsed(o) => assert_eq!(o.repo, "https://bitbucket.org/foo/bar.git"),
        _ => assert!(false),
    }
    match p("https://gitlab.com/foo/bar") {
        ParsedArgv::Parsed(o) => assert_eq!(o.repo, "https://gitlab.com/foo/bar.git"),
        _ => assert!(false),
    }
}

#[test]
fn help_option() {
    match parse_options(&["git-brws", "-h"]).unwrap() {
        ParsedArgv::Help(s) => {
            assert!(s.starts_with("Usage:"));
        }
        _ => assert!(false),
    }
}

#[test]
fn version_option() {
    match parse_options(&["git-brws", "-v"]).unwrap() {
        ParsedArgv::Version(s) => {
            assert!(!s.is_empty());
        }
        _ => assert!(false),
    }
}

#[test]
fn unknown_options() {
    assert!(parse_options(&["git-brws", "--unknown"]).is_err());
}

#[test]
fn detect_git_dir() {
    let current = fs::canonicalize(env::current_dir().unwrap()).unwrap();
    let p = current.join("src").join("test");
    match parse_options(&["git-brws", "-d", p.to_str().unwrap()]).unwrap() {
        ParsedArgv::Parsed(o) => {
            let expected = current.join(".git");
            assert_eq!(o.git_dir, expected);
        }
        p => assert!(false, "{:?}", p),
    }
}
<|endoftext|>


<commit_before>use ascii::{AsciiChar, AsciiStr};
use std::convert::AsRef;
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use ::PASCAL_STRING_BUF_SIZE;

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, _: RangeFull) -> &Self::Output {
        &self.string[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        &mut self.string[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        &self.string[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        &mut self.string[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.string[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.string[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        &self.string[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        &mut self.string[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        &self.string[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        &mut self.string[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        &self.string[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        &mut self.string[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.string[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.string[..range.end]
    }
}

<commit_msg>impl AsRef<[u8]> for PascalStr; impl AsRef<str> for PascalStr; impl ToOwned for PascalStr<commit_after>use ascii::{AsciiChar, AsciiStr};
use std::borrow::ToOwned;
use std::convert::AsRef;
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from_bytes(&self.string).unwrap()
    }
}

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

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, _: RangeFull) -> &Self::Output {
        &self.string[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        &mut self.string[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        &self.string[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        &mut self.string[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.string[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.string[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        &self.string[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        &mut self.string[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        &self.string[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        &mut self.string[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        &self.string[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        &mut self.string[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.string[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.string[..range.end]
    }
}

<|endoftext|>


<commit_before>use std::io::fs::PathExtensions;
use std::io::{File, Open, ReadWrite};
use todo::entry::Entry;

pub struct List {
    file: File,
    entries: Vec<Entry>
}

impl List {
    pub fn new(path: Path) -> List {
        let file = if path.exists() {
            match File::open_mode(&path, Open, ReadWrite) {
                Ok(result) => result,
                Err(reason) => panic!("Couldn't open file `{}` for writing: {}", path.display(), reason.desc)
            }
        } else {
            File::create(&path).unwrap()
        };

        List {
            file: file,
            entries: vec![]
        }
    }

    pub fn load(&mut self) {
        let text = &self.file.read_to_string().unwrap();
        let mut i = 0;
        for line in text.lines() {
            i += 1;
            &self.entries.push(Entry::new(i, line.to_string()));
        }
    }

    pub fn save(&mut self) {
        &self.file.write("Hi!".as_bytes());
    }

    pub fn index(&self, context: Option<String>) {
        for entry in (&self.entries).iter().filter(|current| List::filter(current, &context)) {
            println!("({}) {}", entry.id, entry.content);
        }
    }

    pub fn add(&self, context: Option<String>) {
        println!("adding!");
    }

    pub fn edit(&self, context: Option<String>) {
        println!("editting!");
    }

    pub fn remove(&self, context: Option<String>) {
        println!("removing!");
    }

    pub fn finish(&self, context: Option<String>) {
        println!("finishing!");
    }

    pub fn count(&self, context: Option<String>) {
        println!("counting!");
    }

    fn filter(entry: &&Entry, context: &Option<String>) -> bool {
        match context {
            _ => true
        }
    }
}<commit_msg>Allow entries to be filtered by status<commit_after>use std::io::fs::PathExtensions;
use std::io::{File, Open, ReadWrite};
use std::ascii::AsciiExt;
use todo::entry::Entry;

pub struct List {
    file: File,
    entries: Vec<Entry>
}

impl List {
    pub fn new(path: Path) -> List {
        let file = if path.exists() {
            match File::open_mode(&path, Open, ReadWrite) {
                Ok(result) => result,
                Err(reason) => panic!("Couldn't open file `{}` for writing: {}", path.display(), reason.desc)
            }
        } else {
            File::create(&path).unwrap()
        };

        List {
            file: file,
            entries: vec![]
        }
    }

    pub fn load(&mut self) {
        let text = &self.file.read_to_string().unwrap();
        let mut i = 0;
        for line in text.lines() {
            i += 1;
            &self.entries.push(Entry::new(i, line.to_string()));
        }
    }

    pub fn save(&mut self) {
        &self.file.write("Hi!".as_bytes());
    }

    pub fn index(&self, context: Option<String>) {
        for entry in (&self.entries).iter().filter(|current| List::filter(current, &context)) {
            println!("({}) {}", entry.id, entry.content);
        }
    }

    pub fn add(&self, context: Option<String>) {
        println!("adding!");
    }

    pub fn edit(&self, context: Option<String>) {
        println!("editting!");
    }

    pub fn remove(&self, context: Option<String>) {
        println!("removing!");
    }

    pub fn finish(&self, context: Option<String>) {
        println!("finishing!");
    }

    pub fn count(&self, context: Option<String>) {
        println!("counting!");
    }

    fn filter(entry: &&Entry, context: &Option<String>) -> bool {
        match context.clone() {
            Some(val) => val.eq_ignore_ascii_case(entry.status.as_slice()),
            None => true
        }
    }
}<|endoftext|>


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

use std::iter::Peekable;

#[derive(PartialEq, Show)]
pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-' | '+'     => true,
        _                   => false,
    }
}

pub type PeekableTokens = Peekable<Token, Tokens>;

pub struct Tokens {
    text: String
}

impl Tokens {
    pub fn from_str(input: &str) -> Self {
        Tokens {text: String::from_str(input)}
    }
}

impl Iterator for Tokens {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        let next_char = match self.pop_front() {
            Some(c) => c,
            None => return None,
        };

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let mut number = c.to_string() + self.read_until_whitespace().as_slice();
                number = number.trim_left_matches('+').to_string();
                match number.parse::<f64>() {
                    Some(parsed_num) => Some(Token::Number(parsed_num)),
                    None => panic!("Could not parse number: {}", number),
                }
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokens {
    fn pop_front(&mut self) -> Option<char> {
        match self.text.is_empty() {
            true => None,
            false => Some(self.text.remove(0))
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let next_char = match self.pop_front() {
            Some(c) => c,
            None => return "".to_string(),
        };

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }
}

#[test]
fn test_tokenizer_empty() {
    let test_str = "";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![]);
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Word("hello".to_string()),
    ]);
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Word("hello".to_string()),
        Token::Word("world".to_string()),
    ]);
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Number(4.2),
    ]);
}

#[test]
fn test_tokenizer_1number_plus() {
    let test_str = "+4.2";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Number(4.2),
    ]);
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".4 -2";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Number(0.4),
        Token::Number(-2.0),
    ]);
}

#[test]
fn test_tokenizer_point() {
    let test_str = "POINT (10 -20)";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Word("POINT".to_string()),
        Token::ParenOpen,
        Token::Number(10.0),
        Token::Number(-20.0),
        Token::ParenClose,
    ]);
}
<commit_msg>Update Show -> Debug<commit_after>// Copyright 2014-2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::Peekable;

#[derive(PartialEq, Debug)]
pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-' | '+'     => true,
        _                   => false,
    }
}

pub type PeekableTokens = Peekable<Token, Tokens>;

pub struct Tokens {
    text: String
}

impl Tokens {
    pub fn from_str(input: &str) -> Self {
        Tokens {text: String::from_str(input)}
    }
}

impl Iterator for Tokens {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        let next_char = match self.pop_front() {
            Some(c) => c,
            None => return None,
        };

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let mut number = c.to_string() + self.read_until_whitespace().as_slice();
                number = number.trim_left_matches('+').to_string();
                match number.parse::<f64>() {
                    Some(parsed_num) => Some(Token::Number(parsed_num)),
                    None => panic!("Could not parse number: {}", number),
                }
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokens {
    fn pop_front(&mut self) -> Option<char> {
        match self.text.is_empty() {
            true => None,
            false => Some(self.text.remove(0))
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let next_char = match self.pop_front() {
            Some(c) => c,
            None => return "".to_string(),
        };

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }
}

#[test]
fn test_tokenizer_empty() {
    let test_str = "";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![]);
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Word("hello".to_string()),
    ]);
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Word("hello".to_string()),
        Token::Word("world".to_string()),
    ]);
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Number(4.2),
    ]);
}

#[test]
fn test_tokenizer_1number_plus() {
    let test_str = "+4.2";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Number(4.2),
    ]);
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".4 -2";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Number(0.4),
        Token::Number(-2.0),
    ]);
}

#[test]
fn test_tokenizer_point() {
    let test_str = "POINT (10 -20)";
    let tokens: Vec<Token> = Tokens::from_str(test_str).collect();
    assert_eq!(tokens, vec![
        Token::Word("POINT".to_string()),
        Token::ParenOpen,
        Token::Number(10.0),
        Token::Number(-20.0),
        Token::ParenClose,
    ]);
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use expr::Expr;
use parser::parser_error::ParserError;

#[derive(Debug, PartialEq)]
pub enum RuntimeError {
  SteppingOnValue(Expr),
  UnexpectedExpr(String, Expr),
  VariableNotFound(String),
  InvalidConstAssignment(Expr, String),
  InvalidTypeConversion(String, Expr),
  InvalidMemoryState(String),
  TooManyIterations(usize),
  ParserError(ParserError),
  IntegerOverflow,
  IntegerUnderflow,
}

impl fmt::Display for RuntimeError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      RuntimeError::SteppingOnValue(ref e) => write!(f, "Stepping on a value {:?}", e),
      RuntimeError::UnexpectedExpr(ref s, ref e) => write!(f, "Unexpected expression. Expected {} and found {:?}", s, e),
      RuntimeError::VariableNotFound(ref e) => write!(f, "Variable {:?} does not exist in memory", e),
      RuntimeError::InvalidConstAssignment(ref e, ref s) => write!(f, "Cannot assign {:?} to const {}", e, s),
      RuntimeError::InvalidTypeConversion(ref s, ref e) => write!(f, "Invalid type conversion. Expected {} and found {:?}", s, e),
      RuntimeError::InvalidMemoryState(ref s) => write!(f, "Unexpected internal memory state: {}", s),
      RuntimeError::TooManyIterations(ref n) => write!(f, "Too many iterations while evaluating expression: {}", n),
      RuntimeError::ParserError(ref err) => write!(f, "Parser error: {}", err),
      RuntimeError::IntegerOverflow => write!(f, "Value grew too large"),
      RuntimeError::IntegerUnderflow => write!(f, "Value grew too small"),
    }
  }
}

impl error::Error for RuntimeError {
  fn description(&self) -> &str {
    match *self {
      RuntimeError::SteppingOnValue(_) => "Stepping on a value",
      RuntimeError::UnexpectedExpr(_, _) => "Unexpected expression",
      RuntimeError::VariableNotFound(_) => "Variable does not exist in memory",
      RuntimeError::InvalidConstAssignment(_, _) => "Cannot assign to const",
      RuntimeError::InvalidTypeConversion(_, _) => "Invalid type conversion",
      RuntimeError::InvalidMemoryState(_) => "Unexpected internal memory state",
      RuntimeError::TooManyIterations(_) => "Too many iterations: {}",
      RuntimeError::ParserError(ref err) => err.description(),
      RuntimeError::IntegerOverflow => "Value grew too large",
      RuntimeError::IntegerUnderflow => "Value grew too small",
    }
  }

  fn cause(&self) -> Option<&error::Error> {
    match *self {
      RuntimeError::SteppingOnValue(_) => None,
      RuntimeError::UnexpectedExpr(_, _) => None,
      RuntimeError::VariableNotFound(_) => None,
      RuntimeError::InvalidConstAssignment(_, _) => None,
      RuntimeError::InvalidTypeConversion(_, _) => None,
      RuntimeError::InvalidMemoryState(_) => None,
      RuntimeError::TooManyIterations(_) => None,
      RuntimeError::ParserError(ref err) => Some(err),
      RuntimeError::IntegerOverflow => None,
      RuntimeError::IntegerUnderflow => None,
    }
  }
}

impl From<ParserError> for RuntimeError {
  fn from(err: ParserError) -> RuntimeError {
    RuntimeError::ParserError(err)
  }
}
<commit_msg>more descriptive integer error messages<commit_after>use std::error;
use std::fmt;
use expr::Expr;
use parser::parser_error::ParserError;

#[derive(Debug, PartialEq)]
pub enum RuntimeError {
  SteppingOnValue(Expr),
  UnexpectedExpr(String, Expr),
  VariableNotFound(String),
  InvalidConstAssignment(Expr, String),
  InvalidTypeConversion(String, Expr),
  InvalidMemoryState(String),
  TooManyIterations(usize),
  ParserError(ParserError),
  IntegerOverflow,
  IntegerUnderflow,
}

impl fmt::Display for RuntimeError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      RuntimeError::SteppingOnValue(ref e) => write!(f, "Stepping on a value {:?}", e),
      RuntimeError::UnexpectedExpr(ref s, ref e) => write!(f, "Unexpected expression. Expected {} and found {:?}", s, e),
      RuntimeError::VariableNotFound(ref e) => write!(f, "Variable {:?} does not exist in memory", e),
      RuntimeError::InvalidConstAssignment(ref e, ref s) => write!(f, "Cannot assign {:?} to const {}", e, s),
      RuntimeError::InvalidTypeConversion(ref s, ref e) => write!(f, "Invalid type conversion. Expected {} and found {:?}", s, e),
      RuntimeError::InvalidMemoryState(ref s) => write!(f, "Unexpected internal memory state: {}", s),
      RuntimeError::TooManyIterations(ref n) => write!(f, "Too many iterations while evaluating expression: {}", n),
      RuntimeError::ParserError(ref err) => write!(f, "Parser error: {}", err),
      RuntimeError::IntegerOverflow => write!(f, "Integer overflow: Integer underflow: Value grew too large"),
      RuntimeError::IntegerUnderflow => write!(f, "Integer underflow: Value grew too small"),
    }
  }
}

impl error::Error for RuntimeError {
  fn description(&self) -> &str {
    match *self {
      RuntimeError::SteppingOnValue(_) => "Stepping on a value",
      RuntimeError::UnexpectedExpr(_, _) => "Unexpected expression",
      RuntimeError::VariableNotFound(_) => "Variable does not exist in memory",
      RuntimeError::InvalidConstAssignment(_, _) => "Cannot assign to const",
      RuntimeError::InvalidTypeConversion(_, _) => "Invalid type conversion",
      RuntimeError::InvalidMemoryState(_) => "Unexpected internal memory state",
      RuntimeError::TooManyIterations(_) => "Too many iterations: {}",
      RuntimeError::ParserError(ref err) => err.description(),
      RuntimeError::IntegerOverflow => "Integer overflow: Value grew too large",
      RuntimeError::IntegerUnderflow => "Integer underflow: Value grew too small",
    }
  }

  fn cause(&self) -> Option<&error::Error> {
    match *self {
      RuntimeError::SteppingOnValue(_) => None,
      RuntimeError::UnexpectedExpr(_, _) => None,
      RuntimeError::VariableNotFound(_) => None,
      RuntimeError::InvalidConstAssignment(_, _) => None,
      RuntimeError::InvalidTypeConversion(_, _) => None,
      RuntimeError::InvalidMemoryState(_) => None,
      RuntimeError::TooManyIterations(_) => None,
      RuntimeError::ParserError(ref err) => Some(err),
      RuntimeError::IntegerOverflow => None,
      RuntimeError::IntegerUnderflow => None,
    }
  }
}

impl From<ParserError> for RuntimeError {
  fn from(err: ParserError) -> RuntimeError {
    RuntimeError::ParserError(err)
  }
}
<|endoftext|>