<commit_before>use openssl::ssl;
use std::io::net::ip::Port;
use std::io::net::tcp;
use std::io::net::pipe;
use std::io::{Stream, IoResult};

use {ConnectParams, SslMode, ConnectTarget, ConnectError};
use message;
use message::WriteMessage;
use message::FrontendMessage::SslRequest;

use self::InternalStream::{TcpStream, UnixStream};

const DEFAULT_PORT: Port = 5432;

pub enum MaybeSslStream<S> {
    Ssl(ssl::SslStream<S>),
    Normal(S),
}

impl<S: Stream> Reader for MaybeSslStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.read(buf),
            MaybeSslStream::Normal(ref mut s) => s.read(buf),
        }
    }
}

impl<S: Stream> Writer for MaybeSslStream<S> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.write(buf),
            MaybeSslStream::Normal(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.flush(),
            MaybeSslStream::Normal(ref mut s) => s.flush(),
        }
    }
}

impl MaybeSslStream<InternalStream> {
    #[allow(dead_code)]
    pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.get_inner().set_read_timeout(timeout_ms),
            MaybeSslStream::Normal(ref mut s) => s.set_read_timeout(timeout_ms),
        }
    }
}

pub enum InternalStream {
    TcpStream(tcp::TcpStream),
    UnixStream(pipe::UnixStream),
}

impl Reader for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            TcpStream(ref mut s) => s.read(buf),
            UnixStream(ref mut s) => s.read(buf),
        }
    }
}

impl Writer for InternalStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            TcpStream(ref mut s) => s.write(buf),
            UnixStream(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            TcpStream(ref mut s) => s.flush(),
            UnixStream(ref mut s) => s.flush(),
        }
    }
}

impl InternalStream {
    pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
        match *self {
            TcpStream(ref mut s) => s.set_read_timeout(timeout_ms),
            UnixStream(ref mut s) => s.set_read_timeout(timeout_ms),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) =>
            Ok(try!(tcp::TcpStream::connect((host[], port)).map(TcpStream))),
        ConnectTarget::Unix(ref path) => {
            let mut path = path.clone();
            path.push(format!(".s.PGSQL.{}", port));
            Ok(try!(pipe::UnixStream::connect(&path).map(UnixStream)))
        }
    }
}

pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
                         -> Result<MaybeSslStream<InternalStream>, ConnectError> {
    let mut socket = try!(open_socket(params));

    let (ssl_required, ctx) = match *ssl {
        SslMode::None => return Ok(MaybeSslStream::Normal(socket)),
        SslMode::Prefer(ref ctx) => (false, ctx),
        SslMode::Require(ref ctx) => (true, ctx)
    };

    try!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == 'N' as u8 {
        if ssl_required {
            return Err(ConnectError::NoSslSupport);
        } else {
            return Ok(MaybeSslStream::Normal(socket));
        }
    }

    match ssl::SslStream::new(ctx, socket) {
        Ok(stream) => Ok(MaybeSslStream::Ssl(stream)),
        Err(err) => Err(ConnectError::SslError(err))
    }
}
<commit_msg>More enum cleanup<commit_after>use openssl::ssl;
use std::io::net::ip::Port;
use std::io::net::tcp::TcpStream;
use std::io::net::pipe::UnixStream;
use std::io::{Stream, IoResult};

use {ConnectParams, SslMode, ConnectTarget, ConnectError};
use message;
use message::WriteMessage;
use message::FrontendMessage::SslRequest;

const DEFAULT_PORT: Port = 5432;

pub enum MaybeSslStream<S> {
    Ssl(ssl::SslStream<S>),
    Normal(S),
}

impl<S: Stream> Reader for MaybeSslStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.read(buf),
            MaybeSslStream::Normal(ref mut s) => s.read(buf),
        }
    }
}

impl<S: Stream> Writer for MaybeSslStream<S> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.write(buf),
            MaybeSslStream::Normal(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.flush(),
            MaybeSslStream::Normal(ref mut s) => s.flush(),
        }
    }
}

impl MaybeSslStream<InternalStream> {
    #[allow(dead_code)]
    pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
        match *self {
            MaybeSslStream::Ssl(ref mut s) => s.get_inner().set_read_timeout(timeout_ms),
            MaybeSslStream::Normal(ref mut s) => s.set_read_timeout(timeout_ms),
        }
    }
}

pub enum InternalStream {
    Tcp(TcpStream),
    Unix(UnixStream),
}

impl Reader for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Writer for InternalStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

impl InternalStream {
    pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
        match *self {
            InternalStream::Tcp(ref mut s) => s.set_read_timeout(timeout_ms),
            InternalStream::Unix(ref mut s) => s.set_read_timeout(timeout_ms),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) =>
            Ok(try!(TcpStream::connect((host[], port)).map(InternalStream::Tcp))),
        ConnectTarget::Unix(ref path) => {
            let mut path = path.clone();
            path.push(format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
                         -> Result<MaybeSslStream<InternalStream>, ConnectError> {
    let mut socket = try!(open_socket(params));

    let (ssl_required, ctx) = match *ssl {
        SslMode::None => return Ok(MaybeSslStream::Normal(socket)),
        SslMode::Prefer(ref ctx) => (false, ctx),
        SslMode::Require(ref ctx) => (true, ctx)
    };

    try!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == 'N' as u8 {
        if ssl_required {
            return Err(ConnectError::NoSslSupport);
        } else {
            return Ok(MaybeSslStream::Normal(socket));
        }
    }

    match ssl::SslStream::new(ctx, socket) {
        Ok(stream) => Ok(MaybeSslStream::Ssl(stream)),
        Err(err) => Err(ConnectError::SslError(err))
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] += 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] -= 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}
<commit_msg>Implement wrapping on increment<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        let new_value = match self.cells[self.data_pointer].checked_add(1) {
            None => 0,
            Some(x) => x,
        };
        self.cells[self.data_pointer] = new_value;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] -= 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}
<|endoftext|>


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

#![forbid(unsafe_code)]

use crate::cluster_swarm::cluster_swarm_kube::ClusterSwarmKube;
use anyhow::{format_err, Result};
use debug_interface::AsyncNodeDebugClient;
use libra_config::config::NodeConfig;
use libra_json_rpc_client::{JsonRpcAsyncClient, JsonRpcBatch};
use reqwest::{Client, Url};
use serde_json::Value;
use std::{
    collections::HashSet,
    fmt,
    process::Stdio,
    str::FromStr,
    time::{Duration, Instant},
};
use tokio::{process::Command, time};

#[derive(Debug, Clone, PartialEq)]
pub struct ValidatorGroup {
    pub index: u32,
    pub twin_index: Option<u32>,
}

#[derive(Debug, Clone)]
pub struct InstanceConfig {
    pub validator_group: ValidatorGroup,
    pub application_config: ApplicationConfig,
}

#[derive(Debug, Clone)]
pub enum ApplicationConfig {
    Validator(ValidatorConfig),
    Fullnode(FullnodeConfig),
    LSR(LSRConfig),
    Vault(VaultConfig),
}

#[derive(Debug, Clone)]
pub struct VaultConfig {}

#[derive(Debug, Clone)]
pub struct LSRConfig {
    pub image_tag: String,
    pub lsr_backend: String,
    pub vault_addr: Option<String>,
    pub vault_namespace: Option<String>,
}

#[derive(Debug, Clone)]
pub struct ValidatorConfig {
    pub enable_lsr: bool,
    pub image_tag: String,
    pub safety_rules_addr: Option<String>,
    pub vault_addr: Option<String>,
    pub vault_namespace: Option<String>,
}

#[derive(Debug, Clone)]
pub struct FullnodeConfig {
    pub fullnode_index: u32,
    pub image_tag: String,
    pub seed_peer_ip: String,
    pub vault_addr: Option<String>,
    pub vault_namespace: Option<String>,
}

#[derive(Clone)]
pub struct Instance {
    peer_name: String,
    ip: String,
    ac_port: u32,
    debug_interface_port: Option<u32>,
    http_client: Client,
    backend: InstanceBackend,
}

#[derive(Clone)]
enum InstanceBackend {
    K8S(K8sInstanceInfo),
    Swarm,
}

#[derive(Clone)]
struct K8sInstanceInfo {
    k8s_node: String,
    instance_config: InstanceConfig,
    kube: ClusterSwarmKube,
}

impl ValidatorGroup {
    pub fn new_for_index(index: u32) -> ValidatorGroup {
        Self {
            index,
            twin_index: None,
        }
    }

    pub fn index_only(&self) -> u32 {
        match self.twin_index {
            None => self.index,
            _ => panic!("Only validator has twin index"),
        }
    }
}

impl ApplicationConfig {
    pub fn needs_genesis(&self) -> bool {
        matches!(self, Self::Validator(_)) || matches!(self, Self::Fullnode(_))
    }

    pub fn needs_config(&self) -> bool {
        matches!(self, Self::Validator(_))
            || matches!(self, Self::Fullnode(_))
            || matches!(self, Self::LSR(_))
    }

    pub fn needs_fluentbit(&self) -> bool {
        matches!(self, Self::Validator(_))
            || matches!(self, Self::Fullnode(_))
            || matches!(self, Self::LSR(_))
    }
}

impl InstanceConfig {
    pub fn replace_tag(&mut self, new_tag: String) -> Result<()> {
        match &mut self.application_config {
            ApplicationConfig::Validator(c) => {
                c.image_tag = new_tag;
            }
            ApplicationConfig::Fullnode(c) => {
                c.image_tag = new_tag;
            }
            ApplicationConfig::LSR(c) => {
                c.image_tag = new_tag;
            }
            ApplicationConfig::Vault(..) => {
                return Err(format_err!(
                    "InstanceConfig::Vault does not support custom tags"
                ));
            }
        }
        Ok(())
    }

    pub fn pod_name(&self) -> String {
        match &self.application_config {
            ApplicationConfig::Validator(_) => match self.validator_group.twin_index {
                None => validator_pod_name(self.validator_group.index),
                twin_index => format!(
                    "val-{}-twin-{}",
                    self.validator_group.index,
                    twin_index.unwrap()
                ),
            },
            ApplicationConfig::Fullnode(fullnode_config) => {
                fullnode_pod_name(self.validator_group.index, fullnode_config.fullnode_index)
            }
            ApplicationConfig::LSR(_) => lsr_pod_name(self.validator_group.index),
            ApplicationConfig::Vault(_) => vault_pod_name(self.validator_group.index),
        }
    }

    pub fn make_twin(&mut self, twin_index: u32) {
        self.validator_group.twin_index = Some(twin_index);
    }
}

impl Instance {
    pub fn new(
        peer_name: String,
        ip: String,
        ac_port: u32,
        debug_interface_port: Option<u32>,
        http_client: Client,
    ) -> Instance {
        let backend = InstanceBackend::Swarm;
        Instance {
            peer_name,
            ip,
            ac_port,
            backend,
            debug_interface_port,
            http_client,
        }
    }

    pub fn new_k8s(
        peer_name: String,
        ip: String,
        ac_port: u32,
        k8s_node: String,
        instance_config: InstanceConfig,
        http_client: Client,
        kube: ClusterSwarmKube,
    ) -> Instance {
        let backend = InstanceBackend::K8S(K8sInstanceInfo {
            k8s_node,
            instance_config,
            kube,
        });
        Instance {
            peer_name,
            ip,
            ac_port,
            debug_interface_port: Some(
                NodeConfig::default()
                    .debug_interface
                    .admission_control_node_debug_port as u32,
            ),
            http_client,
            backend,
        }
    }

    pub fn counter(&self, counter: &str) -> Result<f64> {
        let response: Value =
            reqwest::blocking::get(format!("http://{}:9101/counters", self.ip).as_str())?.json()?;
        if let Value::Number(ref response) = response[counter] {
            if let Some(response) = response.as_f64() {
                Ok(response)
            } else {
                Err(format_err!(
                    "Failed to parse counter({}) as f64: {:?}",
                    counter,
                    response
                ))
            }
        } else {
            Err(format_err!(
                "Counter({}) was not a Value::Number: {:?}",
                counter,
                response[counter]
            ))
        }
    }

    pub async fn try_json_rpc(&self) -> Result<()> {
        self.json_rpc_client().execute(JsonRpcBatch::new()).await?;
        Ok(())
    }

    pub async fn wait_json_rpc(&self, deadline: Instant) -> Result<()> {
        while self.try_json_rpc().await.is_err() {
            if Instant::now() > deadline {
                return Err(format_err!("wait_json_rpc for {} timed out", self));
            }
            time::delay_for(Duration::from_secs(3)).await;
        }
        Ok(())
    }

    pub fn peer_name(&self) -> &String {
        &self.peer_name
    }

    pub fn validator_group(&self) -> ValidatorGroup {
        self.k8s_backend().instance_config.validator_group.clone()
    }

    pub fn ip(&self) -> &String {
        &self.ip
    }

    pub fn ac_port(&self) -> u32 {
        self.ac_port
    }

    pub fn json_rpc_url(&self) -> Url {
        Url::from_str(&format!("http://{}:{}/v1", self.ip(), self.ac_port())).expect("Invalid URL.")
    }

    fn k8s_backend(&self) -> &K8sInstanceInfo {
        if let InstanceBackend::K8S(ref k8s) = self.backend {
            return k8s;
        }
        panic!("Instance was not started with k8s");
    }

    pub fn debug_interface_port(&self) -> Option<u32> {
        self.debug_interface_port
    }

    pub fn json_rpc_client(&self) -> JsonRpcAsyncClient {
        JsonRpcAsyncClient::new_with_client(self.http_client.clone(), self.json_rpc_url())
    }

    pub async fn stop(&self) -> Result<()> {
        let backend = self.k8s_backend();
        backend.kube.delete_node(&backend.instance_config).await
    }

    /// Node must be stopped first
    pub async fn start(&self) -> Result<()> {
        let backend = self.k8s_backend();
        backend
            .kube
            .upsert_node(backend.instance_config.clone())
            .await
            .map(|_| ())
    }

    /// If deleting /opt/libra/data/* is required, call Instance::clean_date before calling
    /// Instance::start.
    pub async fn clean_data(&self) -> Result<()> {
        self.util_cmd("rm -rf /opt/libra/data/*; ", "clean-data")
            .await
    }

    pub async fn spawn_job(
        &self,
        docker_image: &str,
        command: &str,
        job_name: &str,
    ) -> Result<String> {
        let backend = self.k8s_backend();
        backend
            .kube
            .spawn_job(&backend.k8s_node, docker_image, command, job_name)
            .await
    }

    pub fn instance_config(&self) -> &InstanceConfig {
        let backend = self.k8s_backend();
        &backend.instance_config
    }

    pub async fn cmd<S: AsRef<str>>(
        &self,
        docker_image: &str,
        command: S,
        job_name: &str,
    ) -> Result<()> {
        let backend = self.k8s_backend();
        backend
            .kube
            .run(&backend.k8s_node, docker_image, command.as_ref(), job_name)
            .await
    }

    /// Runs command on the same host in separate utility container based on cluster-test-util image
    pub async fn util_cmd<S: AsRef<str>>(&self, command: S, job_name: &str) -> Result<()> {
        self.cmd(
            "853397791086.dkr.ecr.us-west-2.amazonaws.com/cluster-test-util:latest",
            command,
            job_name,
        )
        .await
    }

    /// Unlike util_cmd, exec runs command inside the container
    pub async fn exec(&self, command: &str, mute: bool) -> Result<()> {
        let mut cmd = Command::new("kubectl");
        cmd.arg("exec")
            .arg(&self.peer_name)
            .arg("--container")
            .arg("main")
            .arg("--")
            .arg("sh")
            .arg("-c")
            .arg(command)
            .kill_on_drop(true);
        if mute {
            cmd.stdout(Stdio::null()).stderr(Stdio::null());
        }
        let child = cmd.spawn().map_err(|e| {
            format_err!(
                "Failed to spawn child process {} on {}: {}",
                command,
                self.peer_name(),
                e
            )
        })?;
        let status = child
            .await
            .map_err(|e| format_err!("Error running {} on {}: {}", command, self.peer_name(), e))?;
        if !status.success() {
            Err(format_err!(
                "Running {} on {}, exit code {:?}",
                command,
                self.peer_name(),
                status.code()
            ))
        } else {
            Ok(())
        }
    }

    pub fn debug_interface_client(&self) -> AsyncNodeDebugClient {
        AsyncNodeDebugClient::new(
            self.http_client.clone(),
            self.ip(),
            self.debug_interface_port
                .expect("debug_interface_port is not known on this instance") as u16,
        )
    }
}

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

impl fmt::Debug for Instance {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

pub fn instancelist_to_set(instances: &[Instance]) -> HashSet<String> {
    let mut r = HashSet::new();
    for instance in instances {
        r.insert(instance.peer_name().clone());
    }
    r
}

pub fn validator_pod_name(index: u32) -> String {
    format!("val-{}", index)
}

pub fn vault_pod_name(index: u32) -> String {
    format!("vault-{}", index)
}

pub fn lsr_pod_name(index: u32) -> String {
    format!("lsr-{}", index)
}

pub fn fullnode_pod_name(validator_index: u32, fullnode_index: u32) -> String {
    format!("fn-{}-{}", validator_index, fullnode_index)
}
<commit_msg>[cluster-test] removing infinite recursion in Debug implementation<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use crate::cluster_swarm::cluster_swarm_kube::ClusterSwarmKube;
use anyhow::{format_err, Result};
use debug_interface::AsyncNodeDebugClient;
use libra_config::config::NodeConfig;
use libra_json_rpc_client::{JsonRpcAsyncClient, JsonRpcBatch};
use reqwest::{Client, Url};
use serde_json::Value;
use std::{
    collections::HashSet,
    fmt,
    process::Stdio,
    str::FromStr,
    time::{Duration, Instant},
};
use tokio::{process::Command, time};

#[derive(Debug, Clone, PartialEq)]
pub struct ValidatorGroup {
    pub index: u32,
    pub twin_index: Option<u32>,
}

#[derive(Debug, Clone)]
pub struct InstanceConfig {
    pub validator_group: ValidatorGroup,
    pub application_config: ApplicationConfig,
}

#[derive(Debug, Clone)]
pub enum ApplicationConfig {
    Validator(ValidatorConfig),
    Fullnode(FullnodeConfig),
    LSR(LSRConfig),
    Vault(VaultConfig),
}

#[derive(Debug, Clone)]
pub struct VaultConfig {}

#[derive(Debug, Clone)]
pub struct LSRConfig {
    pub image_tag: String,
    pub lsr_backend: String,
    pub vault_addr: Option<String>,
    pub vault_namespace: Option<String>,
}

#[derive(Debug, Clone)]
pub struct ValidatorConfig {
    pub enable_lsr: bool,
    pub image_tag: String,
    pub safety_rules_addr: Option<String>,
    pub vault_addr: Option<String>,
    pub vault_namespace: Option<String>,
}

#[derive(Debug, Clone)]
pub struct FullnodeConfig {
    pub fullnode_index: u32,
    pub image_tag: String,
    pub seed_peer_ip: String,
    pub vault_addr: Option<String>,
    pub vault_namespace: Option<String>,
}

#[derive(Clone)]
pub struct Instance {
    peer_name: String,
    ip: String,
    ac_port: u32,
    debug_interface_port: Option<u32>,
    http_client: Client,
    backend: InstanceBackend,
}

#[derive(Clone)]
enum InstanceBackend {
    K8S(K8sInstanceInfo),
    Swarm,
}

#[derive(Clone)]
struct K8sInstanceInfo {
    k8s_node: String,
    instance_config: InstanceConfig,
    kube: ClusterSwarmKube,
}

impl ValidatorGroup {
    pub fn new_for_index(index: u32) -> ValidatorGroup {
        Self {
            index,
            twin_index: None,
        }
    }

    pub fn index_only(&self) -> u32 {
        match self.twin_index {
            None => self.index,
            _ => panic!("Only validator has twin index"),
        }
    }
}

impl ApplicationConfig {
    pub fn needs_genesis(&self) -> bool {
        matches!(self, Self::Validator(_)) || matches!(self, Self::Fullnode(_))
    }

    pub fn needs_config(&self) -> bool {
        matches!(self, Self::Validator(_))
            || matches!(self, Self::Fullnode(_))
            || matches!(self, Self::LSR(_))
    }

    pub fn needs_fluentbit(&self) -> bool {
        matches!(self, Self::Validator(_))
            || matches!(self, Self::Fullnode(_))
            || matches!(self, Self::LSR(_))
    }
}

impl InstanceConfig {
    pub fn replace_tag(&mut self, new_tag: String) -> Result<()> {
        match &mut self.application_config {
            ApplicationConfig::Validator(c) => {
                c.image_tag = new_tag;
            }
            ApplicationConfig::Fullnode(c) => {
                c.image_tag = new_tag;
            }
            ApplicationConfig::LSR(c) => {
                c.image_tag = new_tag;
            }
            ApplicationConfig::Vault(..) => {
                return Err(format_err!(
                    "InstanceConfig::Vault does not support custom tags"
                ));
            }
        }
        Ok(())
    }

    pub fn pod_name(&self) -> String {
        match &self.application_config {
            ApplicationConfig::Validator(_) => match self.validator_group.twin_index {
                None => validator_pod_name(self.validator_group.index),
                twin_index => format!(
                    "val-{}-twin-{}",
                    self.validator_group.index,
                    twin_index.unwrap()
                ),
            },
            ApplicationConfig::Fullnode(fullnode_config) => {
                fullnode_pod_name(self.validator_group.index, fullnode_config.fullnode_index)
            }
            ApplicationConfig::LSR(_) => lsr_pod_name(self.validator_group.index),
            ApplicationConfig::Vault(_) => vault_pod_name(self.validator_group.index),
        }
    }

    pub fn make_twin(&mut self, twin_index: u32) {
        self.validator_group.twin_index = Some(twin_index);
    }
}

impl Instance {
    pub fn new(
        peer_name: String,
        ip: String,
        ac_port: u32,
        debug_interface_port: Option<u32>,
        http_client: Client,
    ) -> Instance {
        let backend = InstanceBackend::Swarm;
        Instance {
            peer_name,
            ip,
            ac_port,
            backend,
            debug_interface_port,
            http_client,
        }
    }

    pub fn new_k8s(
        peer_name: String,
        ip: String,
        ac_port: u32,
        k8s_node: String,
        instance_config: InstanceConfig,
        http_client: Client,
        kube: ClusterSwarmKube,
    ) -> Instance {
        let backend = InstanceBackend::K8S(K8sInstanceInfo {
            k8s_node,
            instance_config,
            kube,
        });
        Instance {
            peer_name,
            ip,
            ac_port,
            debug_interface_port: Some(
                NodeConfig::default()
                    .debug_interface
                    .admission_control_node_debug_port as u32,
            ),
            http_client,
            backend,
        }
    }

    pub fn counter(&self, counter: &str) -> Result<f64> {
        let response: Value =
            reqwest::blocking::get(format!("http://{}:9101/counters", self.ip).as_str())?.json()?;
        if let Value::Number(ref response) = response[counter] {
            if let Some(response) = response.as_f64() {
                Ok(response)
            } else {
                Err(format_err!(
                    "Failed to parse counter({}) as f64: {:?}",
                    counter,
                    response
                ))
            }
        } else {
            Err(format_err!(
                "Counter({}) was not a Value::Number: {:?}",
                counter,
                response[counter]
            ))
        }
    }

    pub async fn try_json_rpc(&self) -> Result<()> {
        self.json_rpc_client().execute(JsonRpcBatch::new()).await?;
        Ok(())
    }

    pub async fn wait_json_rpc(&self, deadline: Instant) -> Result<()> {
        while self.try_json_rpc().await.is_err() {
            if Instant::now() > deadline {
                return Err(format_err!("wait_json_rpc for {} timed out", self));
            }
            time::delay_for(Duration::from_secs(3)).await;
        }
        Ok(())
    }

    pub fn peer_name(&self) -> &String {
        &self.peer_name
    }

    pub fn validator_group(&self) -> ValidatorGroup {
        self.k8s_backend().instance_config.validator_group.clone()
    }

    pub fn ip(&self) -> &String {
        &self.ip
    }

    pub fn ac_port(&self) -> u32 {
        self.ac_port
    }

    pub fn json_rpc_url(&self) -> Url {
        Url::from_str(&format!("http://{}:{}/v1", self.ip(), self.ac_port())).expect("Invalid URL.")
    }

    fn k8s_backend(&self) -> &K8sInstanceInfo {
        if let InstanceBackend::K8S(ref k8s) = self.backend {
            return k8s;
        }
        panic!("Instance was not started with k8s");
    }

    pub fn debug_interface_port(&self) -> Option<u32> {
        self.debug_interface_port
    }

    pub fn json_rpc_client(&self) -> JsonRpcAsyncClient {
        JsonRpcAsyncClient::new_with_client(self.http_client.clone(), self.json_rpc_url())
    }

    pub async fn stop(&self) -> Result<()> {
        let backend = self.k8s_backend();
        backend.kube.delete_node(&backend.instance_config).await
    }

    /// Node must be stopped first
    pub async fn start(&self) -> Result<()> {
        let backend = self.k8s_backend();
        backend
            .kube
            .upsert_node(backend.instance_config.clone())
            .await
            .map(|_| ())
    }

    /// If deleting /opt/libra/data/* is required, call Instance::clean_date before calling
    /// Instance::start.
    pub async fn clean_data(&self) -> Result<()> {
        self.util_cmd("rm -rf /opt/libra/data/*; ", "clean-data")
            .await
    }

    pub async fn spawn_job(
        &self,
        docker_image: &str,
        command: &str,
        job_name: &str,
    ) -> Result<String> {
        let backend = self.k8s_backend();
        backend
            .kube
            .spawn_job(&backend.k8s_node, docker_image, command, job_name)
            .await
    }

    pub fn instance_config(&self) -> &InstanceConfig {
        let backend = self.k8s_backend();
        &backend.instance_config
    }

    pub async fn cmd<S: AsRef<str>>(
        &self,
        docker_image: &str,
        command: S,
        job_name: &str,
    ) -> Result<()> {
        let backend = self.k8s_backend();
        backend
            .kube
            .run(&backend.k8s_node, docker_image, command.as_ref(), job_name)
            .await
    }

    /// Runs command on the same host in separate utility container based on cluster-test-util image
    pub async fn util_cmd<S: AsRef<str>>(&self, command: S, job_name: &str) -> Result<()> {
        self.cmd(
            "853397791086.dkr.ecr.us-west-2.amazonaws.com/cluster-test-util:latest",
            command,
            job_name,
        )
        .await
    }

    /// Unlike util_cmd, exec runs command inside the container
    pub async fn exec(&self, command: &str, mute: bool) -> Result<()> {
        let mut cmd = Command::new("kubectl");
        cmd.arg("exec")
            .arg(&self.peer_name)
            .arg("--container")
            .arg("main")
            .arg("--")
            .arg("sh")
            .arg("-c")
            .arg(command)
            .kill_on_drop(true);
        if mute {
            cmd.stdout(Stdio::null()).stderr(Stdio::null());
        }
        let child = cmd.spawn().map_err(|e| {
            format_err!(
                "Failed to spawn child process {} on {}: {}",
                command,
                self.peer_name(),
                e
            )
        })?;
        let status = child
            .await
            .map_err(|e| format_err!("Error running {} on {}: {}", command, self.peer_name(), e))?;
        if !status.success() {
            Err(format_err!(
                "Running {} on {}, exit code {:?}",
                command,
                self.peer_name(),
                status.code()
            ))
        } else {
            Ok(())
        }
    }

    pub fn debug_interface_client(&self) -> AsyncNodeDebugClient {
        AsyncNodeDebugClient::new(
            self.http_client.clone(),
            self.ip(),
            self.debug_interface_port
                .expect("debug_interface_port is not known on this instance") as u16,
        )
    }
}

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

impl fmt::Debug for Instance {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

pub fn instancelist_to_set(instances: &[Instance]) -> HashSet<String> {
    let mut r = HashSet::new();
    for instance in instances {
        r.insert(instance.peer_name().clone());
    }
    r
}

pub fn validator_pod_name(index: u32) -> String {
    format!("val-{}", index)
}

pub fn vault_pod_name(index: u32) -> String {
    format!("vault-{}", index)
}

pub fn lsr_pod_name(index: u32) -> String {
    format!("lsr-{}", index)
}

pub fn fullnode_pod_name(validator_index: u32, fullnode_index: u32) -> String {
    format!("fn-{}-{}", validator_index, fullnode_index)
}
<|endoftext|>


<commit_before>use std::result;
use super::BLOCK_SIZE;

pub type Result<T> = result::Result<T, String>;

const movement_speed: f64 = 1.0;

pub static TETROMINOES: [Tetromino; 7] = [
    Tetromino {
        name: Shape::I,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::J,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::L,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::O,
        blocks: [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::S,
        blocks: [[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::T,
        blocks: [[0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::Z,
        blocks: [[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: 0.0,
        y_offset: 0.0
    },
];

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Shape {
    I,
    O,
    T,
    S,
    Z,
    J,
    L
}

#[derive(Debug, Clone, Copy)]
pub struct Tetromino {
    pub name: Shape,
    pub blocks: [[u8; 4]; 4],
    pub x_offset: f64, // offset (in block cell units) of the top left cell
    pub y_offset: f64
}

impl Tetromino {
    pub fn rotate_right(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[4 - c - 1][r];
            }
        }
        self.blocks = new_blocks;
    }

    pub fn rotate_left(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[c][4 - r - 1];
            }
        }

        self.blocks = new_blocks;
    }

    pub fn block_height(&self) -> f64 {
        let mut height = 0.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    height += 1.0;
                    break;
                }
            }
        }
        height
    }

    pub fn block_width(&self) -> f64 {
        let mut cols_vec: [i64; 4] = [0, 0, 0, 0];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    cols_vec[c] = 1;
                }
            }
        }
        let mut width = 0.0;
        for x in cols_vec.iter() {
            if *x == 1 {
                width += 1.0;
            }
        }
        width
    }

    // coordinates of leftmost point in block
    pub fn leftmost(&self) -> f64 {
        let mut leftmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if leftmost > c as f64 {
                        leftmost = c as f64;
                    }
                }
            }
        }
        leftmost + self.x_offset
    }

    pub fn rightmost(&self) -> f64 {
        self.leftmost() + self.block_width() - 1.0
    }

    pub fn topmost(&self) -> f64 {
        let mut topmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if topmost > r as f64 {
                        topmost = r as f64;
                    }
                }
            }
        }
        topmost + self.y_offset
    }

    pub fn bottommost(&self) -> f64 {
        self.topmost() + self.block_height() - 1.0
    }

    pub fn move_down(&mut self) {
        self.y_offset += movement_speed;
    }

    pub fn move_left(&mut self) {
        self.x_offset -= movement_speed;
    }

    pub fn move_right(&mut self) {
        self.x_offset += movement_speed;
    }
}<commit_msg>set spawn location for blocks to middle of board<commit_after>use std::result;
use super::BLOCK_SIZE;
use super::BOARD_WIDTH;
use super::BOARD_HEIGHT;

pub type Result<T> = result::Result<T, String>;

const movement_speed: f64 = 1.0;

pub static TETROMINOES: [Tetromino; 7] = [
    Tetromino {
        name: Shape::I,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::J,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::L,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::O,
        blocks: [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 1.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::S,
        blocks: [[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::T,
        blocks: [[0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0
    },
    Tetromino {
        name: Shape::Z,
        blocks: [[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0
    },
];

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Shape {
    I,
    O,
    T,
    S,
    Z,
    J,
    L
}

#[derive(Debug, Clone, Copy)]
pub struct Tetromino {
    pub name: Shape,
    pub blocks: [[u8; 4]; 4],
    pub x_offset: f64, // offset (in block cell units) of the top left cell
    pub y_offset: f64
}

impl Tetromino {
    pub fn rotate_right(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[4 - c - 1][r];
            }
        }
        self.blocks = new_blocks;
    }

    pub fn rotate_left(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[c][4 - r - 1];
            }
        }

        self.blocks = new_blocks;
    }

    pub fn block_height(&self) -> f64 {
        let mut height = 0.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    height += 1.0;
                    break;
                }
            }
        }
        height
    }

    pub fn block_width(&self) -> f64 {
        let mut cols_vec: [i64; 4] = [0, 0, 0, 0];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    cols_vec[c] = 1;
                }
            }
        }
        let mut width = 0.0;
        for x in cols_vec.iter() {
            if *x == 1 {
                width += 1.0;
            }
        }
        width
    }

    // coordinates of leftmost point in block
    pub fn leftmost(&self) -> f64 {
        let mut leftmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if leftmost > c as f64 {
                        leftmost = c as f64;
                    }
                }
            }
        }
        leftmost + self.x_offset
    }

    pub fn rightmost(&self) -> f64 {
        self.leftmost() + self.block_width() - 1.0
    }

    pub fn topmost(&self) -> f64 {
        let mut topmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if topmost > r as f64 {
                        topmost = r as f64;
                    }
                }
            }
        }
        topmost + self.y_offset
    }

    pub fn bottommost(&self) -> f64 {
        self.topmost() + self.block_height() - 1.0
    }

    pub fn move_down(&mut self) {
        self.y_offset += movement_speed;
    }

    pub fn move_left(&mut self) {
        self.x_offset -= movement_speed;
    }

    pub fn move_right(&mut self) {
        self.x_offset += movement_speed;
    }
}<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::ops::Deref;

use serde::ser::{Serialize, Serializer};

use types::*;

macro_rules! integer_id_impls {
    ($name: ident) => {
        impl $name {
            pub fn new(inner: Integer) -> Self {
                $name(inner)
            }
        }

        impl ::std::fmt::Display for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.0.fmt(f)
            }
        }

        impl From<Integer> for $name {
            fn from(inner: Integer) -> Self {
                $name::new(inner)
            }
        }

        impl From<$name> for Integer {
            fn from(from: $name) -> Self {
                from.0
            }
        }

        impl<'de> ::serde::de::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
                where D: ::serde::de::Deserializer<'de>
            {
                let inner = ::serde::de::Deserialize::deserialize(deserializer)?;
                Ok($name::new(inner))
            }
        }

        impl ::serde::ser::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::ser::Serializer
            {
                serializer.serialize_i64(self.0)
            }
        }
    };
}

pub trait ToSourceChat {
    fn to_source_chat(&self) -> ChatId;
}

impl<S> ToSourceChat for S where S: Deref, S::Target: ToSourceChat {
    fn to_source_chat(&self) -> ChatId {
        self.deref().to_source_chat()
    }
}

impl ToSourceChat for Message {
    fn to_source_chat(&self) -> ChatId {
        self.chat.id()
    }
}

/// Unique identifier for the target chat or username of the
/// target channel (in the format @channelusername)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ChatRef<'a> {
    Id(ChatId),
    #[doc(hidden)]
    ChannelUsername(Cow<'a, str>,),
}

impl<'a> ChatRef<'a> {
    pub fn from_chat_id(chat_id: ChatId) -> ChatRef<'a> {
        ChatRef::Id(chat_id)
    }
}

pub trait ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a>;
}

impl<'a, S> ToChatRef<'a> for S where S: Deref, S::Target: ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.deref().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.clone()
    }
}

impl<'a> ToChatRef<'a> for Chat {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatMember {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.user.to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ForwardFrom {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        match *self {
            ForwardFrom::User {ref user, ..} => user.to_chat_ref(),
            ForwardFrom::Channel {ref channel, ..} => channel.to_chat_ref(),
        }
    }
}

impl<'a> ToChatRef<'a> for Forward {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.from.to_chat_ref()
    }
}

impl<'a> Serialize for ChatRef<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match *self {
            ChatRef::Id(id) => serializer.serialize_i64(id.into()),
            ChatRef::ChannelUsername(ref username) => serializer.serialize_str(&username),
        }
    }
}

macro_rules! chat_id_impls {
    ($id: ident) => {
        integer_id_impls!($id);

        impl<'a> ToChatRef<'a> for $id {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                ChatRef::from_chat_id((*self).into())
            }
        }
    };
}

macro_rules! specific_chat_id_impls {
    ($id: ident, $typ: ident) => {
        chat_id_impls!($id);

        impl From<$id> for ChatId {
            fn from(c: $id) -> Self {
                ChatId::new(c.into())
            }
        }

        impl<'a> ToChatRef<'a> for $typ {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                self.id.to_chat_ref()
            }
        }
    };
}

pub trait ToUserId {
    fn to_user_id(&self) -> UserId;
}

impl<S> ToUserId for S where S: Deref, S::Target: ToUserId {
    fn to_user_id(&self) -> UserId {
        self.deref().to_user_id()
    }
}

impl ToUserId for UserId {
    fn to_user_id(&self) -> UserId {
        *self
    }
}

impl ToUserId for ChatMember {
    fn to_user_id(&self) -> UserId {
        self.user.id
    }
}

impl ToUserId for User {
    fn to_user_id(&self) -> UserId {
        self.id
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(Integer);
specific_chat_id_impls!(UserId, User);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupId(Integer);
specific_chat_id_impls!(GroupId, Group);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SupergroupId(Integer);
specific_chat_id_impls!(SupergroupId, Supergroup);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChannelId(Integer);
specific_chat_id_impls!(ChannelId, Channel);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChatId(Integer);
chat_id_impls!(ChatId);

pub trait ToMessageId {
    fn to_message_id(&self) -> MessageId;
}

impl<S> ToMessageId for S where S: Deref, S::Target: ToMessageId {
    fn to_message_id(&self) -> MessageId {
        self.deref().to_message_id()
    }
}

impl ToMessageId for MessageId {
    fn to_message_id(&self) -> MessageId {
        *self
    }
}

impl ToMessageId for Message {
    fn to_message_id(&self) -> MessageId {
        self.id
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MessageId(Integer);
integer_id_impls!(MessageId);
<commit_msg>docs: document id types<commit_after>use std::borrow::Cow;
use std::ops::Deref;

use serde::ser::{Serialize, Serializer};

use types::*;

macro_rules! integer_id_impls {
    ($name: ident) => {
        impl $name {
            pub fn new(inner: Integer) -> Self {
                $name(inner)
            }
        }

        impl ::std::fmt::Display for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.0.fmt(f)
            }
        }

        impl From<Integer> for $name {
            fn from(inner: Integer) -> Self {
                $name::new(inner)
            }
        }

        impl From<$name> for Integer {
            fn from(from: $name) -> Self {
                from.0
            }
        }

        impl<'de> ::serde::de::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
                where D: ::serde::de::Deserializer<'de>
            {
                let inner = ::serde::de::Deserialize::deserialize(deserializer)?;
                Ok($name::new(inner))
            }
        }

        impl ::serde::ser::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::ser::Serializer
            {
                serializer.serialize_i64(self.0)
            }
        }
    };
}

pub trait ToSourceChat {
    fn to_source_chat(&self) -> ChatId;
}

impl<S> ToSourceChat for S where S: Deref, S::Target: ToSourceChat {
    fn to_source_chat(&self) -> ChatId {
        self.deref().to_source_chat()
    }
}

impl ToSourceChat for Message {
    fn to_source_chat(&self) -> ChatId {
        self.chat.id()
    }
}

/// Unique identifier for the target chat or username of the
/// target channel (in the format @channelusername)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ChatRef<'a> {
    Id(ChatId),
    #[doc(hidden)]
    ChannelUsername(Cow<'a, str>,),
}

impl<'a> ChatRef<'a> {
    pub fn from_chat_id(chat_id: ChatId) -> ChatRef<'a> {
        ChatRef::Id(chat_id)
    }
}

pub trait ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a>;
}

impl<'a, S> ToChatRef<'a> for S where S: Deref, S::Target: ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.deref().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.clone()
    }
}

impl<'a> ToChatRef<'a> for Chat {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatMember {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.user.to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ForwardFrom {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        match *self {
            ForwardFrom::User {ref user, ..} => user.to_chat_ref(),
            ForwardFrom::Channel {ref channel, ..} => channel.to_chat_ref(),
        }
    }
}

impl<'a> ToChatRef<'a> for Forward {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.from.to_chat_ref()
    }
}

impl<'a> Serialize for ChatRef<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match *self {
            ChatRef::Id(id) => serializer.serialize_i64(id.into()),
            ChatRef::ChannelUsername(ref username) => serializer.serialize_str(&username),
        }
    }
}

macro_rules! chat_id_impls {
    ($id: ident) => {
        integer_id_impls!($id);

        impl<'a> ToChatRef<'a> for $id {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                ChatRef::from_chat_id((*self).into())
            }
        }
    };
}

macro_rules! specific_chat_id_impls {
    ($id: ident, $typ: ident) => {
        chat_id_impls!($id);

        impl From<$id> for ChatId {
            fn from(c: $id) -> Self {
                ChatId::new(c.into())
            }
        }

        impl<'a> ToChatRef<'a> for $typ {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                self.id.to_chat_ref()
            }
        }
    };
}

pub trait ToUserId {
    fn to_user_id(&self) -> UserId;
}

impl<S> ToUserId for S where S: Deref, S::Target: ToUserId {
    fn to_user_id(&self) -> UserId {
        self.deref().to_user_id()
    }
}

impl ToUserId for UserId {
    fn to_user_id(&self) -> UserId {
        *self
    }
}

impl ToUserId for ChatMember {
    fn to_user_id(&self) -> UserId {
        self.user.id
    }
}

impl ToUserId for User {
    fn to_user_id(&self) -> UserId {
        self.id
    }
}

/// Unique user identifier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(Integer);
specific_chat_id_impls!(UserId, User);

/// Unique group identifier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupId(Integer);
specific_chat_id_impls!(GroupId, Group);

/// Unique supergroup identifier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SupergroupId(Integer);
specific_chat_id_impls!(SupergroupId, Supergroup);

/// Unique channel identifier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChannelId(Integer);
specific_chat_id_impls!(ChannelId, Channel);

/// Unique chat identifier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChatId(Integer);
chat_id_impls!(ChatId);

pub trait ToMessageId {
    fn to_message_id(&self) -> MessageId;
}

impl<S> ToMessageId for S where S: Deref, S::Target: ToMessageId {
    fn to_message_id(&self) -> MessageId {
        self.deref().to_message_id()
    }
}

impl ToMessageId for MessageId {
    fn to_message_id(&self) -> MessageId {
        *self
    }
}

impl ToMessageId for Message {
    fn to_message_id(&self) -> MessageId {
        self.id
    }
}

/// Unique message identifier inside a chat.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MessageId(Integer);
integer_id_impls!(MessageId);
<|endoftext|>


<commit_before>extern crate image;

use std::io::File;

fn main() {
    println!("24 days of Rust - image (day 12)");
    let img = image::open(&Path::new("data/in.jpg")).ok().expect("Opening image failed");
    let filtered = img.fliph();
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = filtered.save(out, image::JPEG).ok().expect("Saving image failed");
}
<commit_msg>Edge detection filter.<commit_after>extern crate image;

use std::io::File;

fn main() {
    println!("24 days of Rust - image (day 12)");
    let img = image::open(&Path::new("data/in.jpg")).ok().expect("Opening image failed");
    let filtered = img.fliph();
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = filtered.save(out, image::JPEG).ok().expect("Saving image failed");

    let kernel = [-1.0f32, -1.0, -1.0,
                  -1.0, 8.0, -1.0,
                  -1.0, -1.0, -1.0];
    let filtered = img.filter3x3(&kernel);
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = filtered.save(out, image::JPEG).ok().expect("Saving image failed");
}
<|endoftext|>


<commit_before>use git2::Error as GitError;
use std::env::VarError;
use std::error::Error as StdError;

use std::fmt;
use std::convert::From;

use self::Error::*;

#[derive(Debug)]
pub enum Error {
    Git(GitError),
    Var(VarError),
}

impl From<GitError> for Error {
    fn from(err: GitError) -> Error {
        Error::Git(err)
    }
}

impl From<VarError> for Error {
    fn from(err: VarError) -> Error {
        Error::Var(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Git(ref e) => e.fmt(f),
            Var(ref e) => e.fmt(f),
        }

    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Git(ref e) => e.description(),
            Var(ref e) => e.description(),
        }
    }
}
<commit_msg>feat: Handle IoError<commit_after>use git2::Error as GitError;
use std::env::VarError;
use std::error::Error as StdError;
use std::io::Error as IoError;

use std::fmt;
use std::convert::From;

use self::Error::*;

#[derive(Debug)]
pub enum Error {
    Git(GitError),
    Var(VarError),
    Io(IoError),
}

impl From<GitError> for Error {
    fn from(err: GitError) -> Error {
        Error::Git(err)
    }
}

impl From<VarError> for Error {
    fn from(err: VarError) -> Error {
        Error::Var(err)
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Git(ref e) => e.fmt(f),
            Var(ref e) => e.fmt(f),
            Io(ref e) => e.fmt(f),
        }

    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Git(ref e) => e.description(),
            Var(ref e) => e.description(),
            Io(ref e) => e.description(),
        }
    }
}
<|endoftext|>


<commit_before>//! Error type used in the library

use std;
use std::fmt;
use std::ops::Deref;

pub type Result<T> = std::result::Result<T, Error>;

/// Error type
#[derive(Debug)]
pub struct Error {
	// Description
	what: String,
	// Cause
	cause: Option<Box<std::error::Error + Sized>>,
}

impl Error {
	/// Construct `Error` with message only
	pub fn new<S>(what: S) -> Self
		where S: Into<String> {
		Error {
			what: what.into(),
			cause: None,
		}
	}

	/// Consumes self and constructs `Error` with message and cause
	pub fn because<E>(self, cause: E) -> Self
		where E: 'static + std::error::Error + Sized {
		Error {
			what: self.what,
			cause: Some(Box::new(cause)),
		}
	}

	/// Consumes self and retuns `Err` variant of `Result<T, Error>`.
	pub fn result<T>(self) -> Result<T> {
		Err(self)
	}
}

impl std::error::Error for Error {
	fn description(&self) -> &str {
		&self.what
	}

	fn cause(&self) -> Option<&std::error::Error> {
		match self.cause {
			None => None,
			Some(ref boxed) => Some(boxed.deref())
		}
	}
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self.cause {
			None => write!(f, "{}", self.what),
			Some(ref boxed) => write!(f, "{} because {}", self.what, &boxed),
		}
    }
}
<commit_msg>Parse error from JSON<commit_after>//! Error type used in the library

use std;
use std::fmt;
use std::ops::Deref;
use serde_json::Value;

pub type Result<T> = std::result::Result<T, Error>;

/// Error type
#[derive(Debug)]
pub struct Error {
	// Description
	what: String,
	// Cause
	cause: Option<Box<std::error::Error + Sized>>,
}

impl Error {
	/// Construct `Error` with message only
	pub fn new<S>(what: S) -> Self
		where S: Into<String> {
		Error {
			what: what.into(),
			cause: None,
		}
	}

	/// Consumes self and constructs `Error` with message and cause
	pub fn because<E>(self, cause: E) -> Self
		where E: 'static + std::error::Error + Sized {
		Error {
			what: self.what,
			cause: Some(Box::new(cause)),
		}
	}

	/// Consumes self and retuns `Err` variant of `Result<T, Error>`.
	pub fn result<T>(self) -> Result<T> {
		Err(self)
	}

	// Parse the error from the result JSON
	pub fn from_json(value: Value) -> Result<Value> {
		match value.clone().find("code") {
			Some(code_value) => {
				// Get error code
				let code = code_value.as_string()
					.unwrap();

				// Get error message
				let message = value.find("message")
					.unwrap()
					.find("value")
					.unwrap()
					.as_string()
					.unwrap();

				Error::new(format!("{}: {}", code, message)).result()
			},
			None => Ok(value)
		}
	}
}

impl std::error::Error for Error {
	fn description(&self) -> &str {
		&self.what
	}

	fn cause(&self) -> Option<&std::error::Error> {
		match self.cause {
			None => None,
			Some(ref boxed) => Some(boxed.deref())
		}
	}
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self.cause {
			None => write!(f, "{}", self.what),
			Some(ref boxed) => write!(f, "{} because {}", self.what, &boxed),
		}
    }
}
<|endoftext|>


<commit_before>//! Error and Result module
use std::{fmt, result};
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::io::Error as IoError;

use cookie;
use httparse;
use failure::Fail;
use http2::Error as Http2Error;
use http::{header, StatusCode, Error as HttpError};
use http_range::HttpRangeParseError;

// re-exports
pub use cookie::{ParseError as CookieParseError};

use body::Body;
use httpresponse::HttpResponse;
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed, HTTPExpectationFailed};

/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
/// for actix web operations
///
/// This typedef is generally used to avoid writing out `actix_web::error::Error` directly and
/// is otherwise a direct mapping to `Result`.
pub type Result<T> = result::Result<T, Error>;

/// Actix web error
#[derive(Debug)]
pub struct Error {
    cause: Box<ErrorResponse>,
}

impl Error {

    /// Returns a reference to the underlying cause of this Error.
    // this should return &Fail but needs this https://github.com/rust-lang/rust/issues/5665
    pub fn cause(&self) -> &ErrorResponse {
        self.cause.as_ref()
    }
}

/// Error that can be converted to `HttpResponse`
pub trait ErrorResponse: Fail {

    /// Create response for error
    ///
    /// Internal server error is generated by default.
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Body::Empty)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.cause, f)
    }
}

/// `HttpResponse` for `Error`
impl From<Error> for HttpResponse {
    fn from(err: Error) -> Self {
        err.cause.error_response()
    }
}

impl<T: ErrorResponse> From<T> for Error {
    fn from(err: T) -> Error {
        Error { cause: Box::new(err) }
    }
}

// /// Default error is `InternalServerError`
// impl<T: StdError + Sync + Send + 'static> ErrorResponse for T {
//     fn error_response(&self) -> HttpResponse {
//         HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Body::Empty)
//     }
// }

/// A set of errors that can occur during parsing HTTP streams
#[derive(Fail, Debug)]
pub enum ParseError {
    /// An invalid `Method`, such as `GE.T`.
    #[fail(display="Invalid Method specified")]
    Method,
    /// An invalid `Uri`, such as `exam ple.domain`.
    #[fail(display="Uri error")]
    Uri,
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    #[fail(display="Invalid HTTP version specified")]
    Version,
    /// An invalid `Header`.
    #[fail(display="Invalid Header provided")]
    Header,
    /// A message head is too large to be reasonable.
    #[fail(display="Message head is too large")]
    TooLarge,
    /// A message reached EOF, but is not complete.
    #[fail(display="Message is incomplete")]
    Incomplete,
    /// An invalid `Status`, such as `1337 ELITE`.
    #[fail(display="Invalid Status provided")]
    Status,
    /// A timeout occurred waiting for an IO event.
    #[allow(dead_code)]
    #[fail(display="Timeout")]
    Timeout,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    #[fail(display="IO error: {}", _0)]
    Io(#[cause] IoError),
    /// Parsing a field as string failed
    #[fail(display="UTF8 error: {}", _0)]
    Utf8(#[cause] Utf8Error),
}

/// Return `BadRequest` for `ParseError`
impl ErrorResponse for ParseError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
    }
}

impl From<IoError> for ParseError {
    fn from(err: IoError) -> ParseError {
        ParseError::Io(err)
    }
}

impl From<Utf8Error> for ParseError {
    fn from(err: Utf8Error) -> ParseError {
        ParseError::Utf8(err)
    }
}

impl From<FromUtf8Error> for ParseError {
    fn from(err: FromUtf8Error) -> ParseError {
        ParseError::Utf8(err.utf8_error())
    }
}

impl From<httparse::Error> for ParseError {
    fn from(err: httparse::Error) -> ParseError {
        match err {
            httparse::Error::HeaderName |
            httparse::Error::HeaderValue |
            httparse::Error::NewLine |
            httparse::Error::Token => ParseError::Header,
            httparse::Error::Status => ParseError::Status,
            httparse::Error::TooManyHeaders => ParseError::TooLarge,
            httparse::Error::Version => ParseError::Version,
        }
    }
}

#[derive(Fail, Debug)]
/// A set of errors that can occur during payload parsing
pub enum PayloadError {
    /// A payload reached EOF, but is not complete.
    #[fail(display="A payload reached EOF, but is not complete.")]
    Incomplete,
    /// Content encoding stream corruption
    #[fail(display="Can not decode content-encoding.")]
    EncodingCorrupted,
    /// Parse error
    #[fail(display="{}", _0)]
    ParseError(#[cause] IoError),
    /// Http2 error
    #[fail(display="{}", _0)]
    Http2(#[cause] Http2Error),
}

impl From<IoError> for PayloadError {
    fn from(err: IoError) -> PayloadError {
        PayloadError::ParseError(err)
    }
}

/// Return `InternalServerError` for `HttpError`,
/// Response generation can return `HttpError`, so it is internal error
impl ErrorResponse for HttpError {}

/// Return `InternalServerError` for `io::Error`
impl ErrorResponse for IoError {}

/// Return `BadRequest` for `cookie::ParseError`
impl ErrorResponse for cookie::ParseError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
    }
}

/// Http range header parsing error
#[derive(Fail, Debug)]
pub enum HttpRangeError {
    /// Returned if range is invalid.
    #[fail(display="Range header is invalid")]
    InvalidRange,
    /// Returned if first-byte-pos of all of the byte-range-spec
    /// values is greater than the content size.
    /// See https://github.com/golang/go/commit/aa9b3d7
    #[fail(display="First-byte-pos of all of the byte-range-spec values is greater than the content size")]
    NoOverlap,
}

/// Return `BadRequest` for `HttpRangeError`
impl ErrorResponse for HttpRangeError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(
            StatusCode::BAD_REQUEST, Body::from("Invalid Range header provided"))
    }
}

impl From<HttpRangeParseError> for HttpRangeError {
    fn from(err: HttpRangeParseError) -> HttpRangeError {
        match err {
            HttpRangeParseError::InvalidRange => HttpRangeError::InvalidRange,
            HttpRangeParseError::NoOverlap => HttpRangeError::NoOverlap,
        }
    }
}

/// A set of errors that can occur during parsing multipart streams
#[derive(Fail, Debug)]
pub enum MultipartError {
    /// Content-Type header is not found
    #[fail(display="No Content-type header found")]
    NoContentType,
    /// Can not parse Content-Type header
    #[fail(display="Can not parse Content-Type header")]
    ParseContentType,
    /// Multipart boundary is not found
    #[fail(display="Multipart boundary is not found")]
    Boundary,
    /// Error during field parsing
    #[fail(display="{}", _0)]
    Parse(#[cause] ParseError),
    /// Payload error
    #[fail(display="{}", _0)]
    Payload(#[cause] PayloadError),
}

impl From<ParseError> for MultipartError {
    fn from(err: ParseError) -> MultipartError {
        MultipartError::Parse(err)
    }
}

impl From<PayloadError> for MultipartError {
    fn from(err: PayloadError) -> MultipartError {
        MultipartError::Payload(err)
    }
}

/// Return `BadRequest` for `MultipartError`
impl ErrorResponse for MultipartError {

    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
    }
}

/// Error during handling `Expect` header
#[derive(Fail, PartialEq, Debug)]
pub enum ExpectError {
    /// Expect header value can not be converted to utf8
    #[fail(display="Expect header value can not be converted to utf8")]
    Encoding,
    /// Unknown expect value
    #[fail(display="Unknown expect value")]
    UnknownExpect,
}

impl ErrorResponse for ExpectError {

    fn error_response(&self) -> HttpResponse {
        HTTPExpectationFailed.with_body("Unknown Expect")
    }
}

/// Websocket handshake errors
#[derive(Fail, PartialEq, Debug)]
pub enum WsHandshakeError {
    /// Only get method is allowed
    #[fail(display="Method not allowed")]
    GetMethodRequired,
    /// Ugrade header if not set to websocket
    #[fail(display="Websocket upgrade is expected")]
    NoWebsocketUpgrade,
    /// Connection header is not set to upgrade
    #[fail(display="Connection upgrade is expected")]
    NoConnectionUpgrade,
    /// Websocket version header is not set
    #[fail(display="Websocket version header is required")]
    NoVersionHeader,
    /// Unsupported websockt version
    #[fail(display="Unsupported version")]
    UnsupportedVersion,
    /// Websocket key is not set or wrong
    #[fail(display="Unknown websocket key")]
    BadWebsocketKey,
}

impl ErrorResponse for WsHandshakeError {

    fn error_response(&self) -> HttpResponse {
        match *self {
            WsHandshakeError::GetMethodRequired => {
                HTTPMethodNotAllowed
                    .builder()
                    .header(header::ALLOW, "GET")
                    .finish()
                    .unwrap()
            }
            WsHandshakeError::NoWebsocketUpgrade =>
                HTTPBadRequest.with_reason("No WebSocket UPGRADE header found"),
            WsHandshakeError::NoConnectionUpgrade =>
                HTTPBadRequest.with_reason("No CONNECTION upgrade"),
            WsHandshakeError::NoVersionHeader =>
                HTTPBadRequest.with_reason("Websocket version header is required"),
            WsHandshakeError::UnsupportedVersion =>
                HTTPBadRequest.with_reason("Unsupported version"),
            WsHandshakeError::BadWebsocketKey =>
                HTTPBadRequest.with_reason("Handshake error")
        }
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error as StdError;
    use std::io;
    use httparse;
    use http::{StatusCode, Error as HttpError};
    use cookie::ParseError as CookieParseError;
    use super::*;

    #[test]
    fn test_into_response() {
        let resp: HttpResponse = ParseError::Incomplete.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let resp: HttpResponse = HttpRangeError::InvalidRange.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let resp: HttpResponse = CookieParseError::EmptyName.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let resp: HttpResponse = MultipartError::Boundary.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
        let resp: HttpResponse = err.error_response();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    #[test]
    fn test_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = ParseError::Io(orig);
        assert_eq!(format!("{}", e.cause().unwrap()), desc);
    }

    #[test]
    fn test_error_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = Error::from(orig);
        assert_eq!(format!("{}", e.cause()), desc);
    }

    macro_rules! from {
        ($from:expr => $error:pat) => {
            match ParseError::from($from) {
                e @ $error => {
                    assert!(format!("{}", e).len() >= 5);
                } ,
                e => panic!("{:?}", e)
            }
        }
    }

    macro_rules! from_and_cause {
        ($from:expr => $error:pat) => {
            match ParseError::from($from) {
                e @ $error => {
                    let desc = format!("{}", e.cause().unwrap());
                    assert_eq!(desc, $from.description().to_owned());
                },
                _ => panic!("{:?}", $from)
            }
        }
    }

    #[test]
    fn test_from() {
        from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => ParseError::Io(..));

        from!(httparse::Error::HeaderName => ParseError::Header);
        from!(httparse::Error::HeaderName => ParseError::Header);
        from!(httparse::Error::HeaderValue => ParseError::Header);
        from!(httparse::Error::NewLine => ParseError::Header);
        from!(httparse::Error::Status => ParseError::Status);
        from!(httparse::Error::Token => ParseError::Header);
        from!(httparse::Error::TooManyHeaders => ParseError::TooLarge);
        from!(httparse::Error::Version => ParseError::Version);
    }
}
<commit_msg>add tests for errors<commit_after>//! Error and Result module
use std::{fmt, result};
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::io::Error as IoError;

use cookie;
use httparse;
use failure::Fail;
use http2::Error as Http2Error;
use http::{header, StatusCode, Error as HttpError};
use http_range::HttpRangeParseError;

// re-exports
pub use cookie::{ParseError as CookieParseError};

use body::Body;
use httpresponse::HttpResponse;
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed, HTTPExpectationFailed};

/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
/// for actix web operations
///
/// This typedef is generally used to avoid writing out `actix_web::error::Error` directly and
/// is otherwise a direct mapping to `Result`.
pub type Result<T> = result::Result<T, Error>;

/// Actix web error
#[derive(Debug)]
pub struct Error {
    cause: Box<ErrorResponse>,
}

impl Error {

    /// Returns a reference to the underlying cause of this Error.
    // this should return &Fail but needs this https://github.com/rust-lang/rust/issues/5665
    pub fn cause(&self) -> &ErrorResponse {
        self.cause.as_ref()
    }
}

/// Error that can be converted to `HttpResponse`
pub trait ErrorResponse: Fail {

    /// Create response for error
    ///
    /// Internal server error is generated by default.
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Body::Empty)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.cause, f)
    }
}

/// `HttpResponse` for `Error`
impl From<Error> for HttpResponse {
    fn from(err: Error) -> Self {
        err.cause.error_response()
    }
}

impl<T: ErrorResponse> From<T> for Error {
    fn from(err: T) -> Error {
        Error { cause: Box::new(err) }
    }
}

// /// Default error is `InternalServerError`
// impl<T: StdError + Sync + Send + 'static> ErrorResponse for T {
//     fn error_response(&self) -> HttpResponse {
//         HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Body::Empty)
//     }
// }

/// A set of errors that can occur during parsing HTTP streams
#[derive(Fail, Debug)]
pub enum ParseError {
    /// An invalid `Method`, such as `GE.T`.
    #[fail(display="Invalid Method specified")]
    Method,
    /// An invalid `Uri`, such as `exam ple.domain`.
    #[fail(display="Uri error")]
    Uri,
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    #[fail(display="Invalid HTTP version specified")]
    Version,
    /// An invalid `Header`.
    #[fail(display="Invalid Header provided")]
    Header,
    /// A message head is too large to be reasonable.
    #[fail(display="Message head is too large")]
    TooLarge,
    /// A message reached EOF, but is not complete.
    #[fail(display="Message is incomplete")]
    Incomplete,
    /// An invalid `Status`, such as `1337 ELITE`.
    #[fail(display="Invalid Status provided")]
    Status,
    /// A timeout occurred waiting for an IO event.
    #[allow(dead_code)]
    #[fail(display="Timeout")]
    Timeout,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    #[fail(display="IO error: {}", _0)]
    Io(#[cause] IoError),
    /// Parsing a field as string failed
    #[fail(display="UTF8 error: {}", _0)]
    Utf8(#[cause] Utf8Error),
}

/// Return `BadRequest` for `ParseError`
impl ErrorResponse for ParseError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
    }
}

impl From<IoError> for ParseError {
    fn from(err: IoError) -> ParseError {
        ParseError::Io(err)
    }
}

impl From<Utf8Error> for ParseError {
    fn from(err: Utf8Error) -> ParseError {
        ParseError::Utf8(err)
    }
}

impl From<FromUtf8Error> for ParseError {
    fn from(err: FromUtf8Error) -> ParseError {
        ParseError::Utf8(err.utf8_error())
    }
}

impl From<httparse::Error> for ParseError {
    fn from(err: httparse::Error) -> ParseError {
        match err {
            httparse::Error::HeaderName |
            httparse::Error::HeaderValue |
            httparse::Error::NewLine |
            httparse::Error::Token => ParseError::Header,
            httparse::Error::Status => ParseError::Status,
            httparse::Error::TooManyHeaders => ParseError::TooLarge,
            httparse::Error::Version => ParseError::Version,
        }
    }
}

#[derive(Fail, Debug)]
/// A set of errors that can occur during payload parsing
pub enum PayloadError {
    /// A payload reached EOF, but is not complete.
    #[fail(display="A payload reached EOF, but is not complete.")]
    Incomplete,
    /// Content encoding stream corruption
    #[fail(display="Can not decode content-encoding.")]
    EncodingCorrupted,
    /// Parse error
    #[fail(display="{}", _0)]
    ParseError(#[cause] IoError),
    /// Http2 error
    #[fail(display="{}", _0)]
    Http2(#[cause] Http2Error),
}

impl From<IoError> for PayloadError {
    fn from(err: IoError) -> PayloadError {
        PayloadError::ParseError(err)
    }
}

/// Return `InternalServerError` for `HttpError`,
/// Response generation can return `HttpError`, so it is internal error
impl ErrorResponse for HttpError {}

/// Return `InternalServerError` for `io::Error`
impl ErrorResponse for IoError {}

/// Return `BadRequest` for `cookie::ParseError`
impl ErrorResponse for cookie::ParseError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
    }
}

/// Http range header parsing error
#[derive(Fail, PartialEq, Debug)]
pub enum HttpRangeError {
    /// Returned if range is invalid.
    #[fail(display="Range header is invalid")]
    InvalidRange,
    /// Returned if first-byte-pos of all of the byte-range-spec
    /// values is greater than the content size.
    /// See https://github.com/golang/go/commit/aa9b3d7
    #[fail(display="First-byte-pos of all of the byte-range-spec values is greater than the content size")]
    NoOverlap,
}

/// Return `BadRequest` for `HttpRangeError`
impl ErrorResponse for HttpRangeError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(
            StatusCode::BAD_REQUEST, Body::from("Invalid Range header provided"))
    }
}

impl From<HttpRangeParseError> for HttpRangeError {
    fn from(err: HttpRangeParseError) -> HttpRangeError {
        match err {
            HttpRangeParseError::InvalidRange => HttpRangeError::InvalidRange,
            HttpRangeParseError::NoOverlap => HttpRangeError::NoOverlap,
        }
    }
}

/// A set of errors that can occur during parsing multipart streams
#[derive(Fail, Debug)]
pub enum MultipartError {
    /// Content-Type header is not found
    #[fail(display="No Content-type header found")]
    NoContentType,
    /// Can not parse Content-Type header
    #[fail(display="Can not parse Content-Type header")]
    ParseContentType,
    /// Multipart boundary is not found
    #[fail(display="Multipart boundary is not found")]
    Boundary,
    /// Error during field parsing
    #[fail(display="{}", _0)]
    Parse(#[cause] ParseError),
    /// Payload error
    #[fail(display="{}", _0)]
    Payload(#[cause] PayloadError),
}

impl From<ParseError> for MultipartError {
    fn from(err: ParseError) -> MultipartError {
        MultipartError::Parse(err)
    }
}

impl From<PayloadError> for MultipartError {
    fn from(err: PayloadError) -> MultipartError {
        MultipartError::Payload(err)
    }
}

/// Return `BadRequest` for `MultipartError`
impl ErrorResponse for MultipartError {

    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
    }
}

/// Error during handling `Expect` header
#[derive(Fail, PartialEq, Debug)]
pub enum ExpectError {
    /// Expect header value can not be converted to utf8
    #[fail(display="Expect header value can not be converted to utf8")]
    Encoding,
    /// Unknown expect value
    #[fail(display="Unknown expect value")]
    UnknownExpect,
}

impl ErrorResponse for ExpectError {

    fn error_response(&self) -> HttpResponse {
        HTTPExpectationFailed.with_body("Unknown Expect")
    }
}

/// Websocket handshake errors
#[derive(Fail, PartialEq, Debug)]
pub enum WsHandshakeError {
    /// Only get method is allowed
    #[fail(display="Method not allowed")]
    GetMethodRequired,
    /// Ugrade header if not set to websocket
    #[fail(display="Websocket upgrade is expected")]
    NoWebsocketUpgrade,
    /// Connection header is not set to upgrade
    #[fail(display="Connection upgrade is expected")]
    NoConnectionUpgrade,
    /// Websocket version header is not set
    #[fail(display="Websocket version header is required")]
    NoVersionHeader,
    /// Unsupported websockt version
    #[fail(display="Unsupported version")]
    UnsupportedVersion,
    /// Websocket key is not set or wrong
    #[fail(display="Unknown websocket key")]
    BadWebsocketKey,
}

impl ErrorResponse for WsHandshakeError {

    fn error_response(&self) -> HttpResponse {
        match *self {
            WsHandshakeError::GetMethodRequired => {
                HTTPMethodNotAllowed
                    .builder()
                    .header(header::ALLOW, "GET")
                    .finish()
                    .unwrap()
            }
            WsHandshakeError::NoWebsocketUpgrade =>
                HTTPBadRequest.with_reason("No WebSocket UPGRADE header found"),
            WsHandshakeError::NoConnectionUpgrade =>
                HTTPBadRequest.with_reason("No CONNECTION upgrade"),
            WsHandshakeError::NoVersionHeader =>
                HTTPBadRequest.with_reason("Websocket version header is required"),
            WsHandshakeError::UnsupportedVersion =>
                HTTPBadRequest.with_reason("Unsupported version"),
            WsHandshakeError::BadWebsocketKey =>
                HTTPBadRequest.with_reason("Handshake error")
        }
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error as StdError;
    use std::io;
    use httparse;
    use http::{StatusCode, Error as HttpError};
    use cookie::ParseError as CookieParseError;
    use super::*;

    #[test]
    fn test_into_response() {
        let resp: HttpResponse = ParseError::Incomplete.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let resp: HttpResponse = HttpRangeError::InvalidRange.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let resp: HttpResponse = CookieParseError::EmptyName.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let resp: HttpResponse = MultipartError::Boundary.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
        let resp: HttpResponse = err.error_response();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    #[test]
    fn test_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = ParseError::Io(orig);
        assert_eq!(format!("{}", e.cause().unwrap()), desc);
    }

    #[test]
    fn test_error_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = Error::from(orig);
        assert_eq!(format!("{}", e.cause()), desc);
    }

    #[test]
    fn test_error_display() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = Error::from(orig);
        assert_eq!(format!("{}", e), desc);
    }

    #[test]
    fn test_error_http_response() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let e = Error::from(orig);
        let resp: HttpResponse = e.into();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    #[test]
    fn test_range_error() {
        let e: HttpRangeError = HttpRangeParseError::InvalidRange.into();
        assert_eq!(e, HttpRangeError::InvalidRange);
        let e: HttpRangeError = HttpRangeParseError::NoOverlap.into();
        assert_eq!(e, HttpRangeError::NoOverlap);
    }

    #[test]
    fn test_wserror_http_response() {
        let resp: HttpResponse = WsHandshakeError::GetMethodRequired.error_response();
        assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
        let resp: HttpResponse = WsHandshakeError::NoWebsocketUpgrade.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
        let resp: HttpResponse = WsHandshakeError::NoConnectionUpgrade.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
        let resp: HttpResponse = WsHandshakeError::NoVersionHeader.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
        let resp: HttpResponse = WsHandshakeError::UnsupportedVersion.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
        let resp: HttpResponse = WsHandshakeError::BadWebsocketKey.error_response();
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
    }

    macro_rules! from {
        ($from:expr => $error:pat) => {
            match ParseError::from($from) {
                e @ $error => {
                    assert!(format!("{}", e).len() >= 5);
                } ,
                e => panic!("{:?}", e)
            }
        }
    }

    macro_rules! from_and_cause {
        ($from:expr => $error:pat) => {
            match ParseError::from($from) {
                e @ $error => {
                    let desc = format!("{}", e.cause().unwrap());
                    assert_eq!(desc, $from.description().to_owned());
                },
                _ => panic!("{:?}", $from)
            }
        }
    }

    #[test]
    fn test_from() {
        from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => ParseError::Io(..));

        from!(httparse::Error::HeaderName => ParseError::Header);
        from!(httparse::Error::HeaderName => ParseError::Header);
        from!(httparse::Error::HeaderValue => ParseError::Header);
        from!(httparse::Error::NewLine => ParseError::Header);
        from!(httparse::Error::Status => ParseError::Status);
        from!(httparse::Error::Token => ParseError::Header);
        from!(httparse::Error::TooManyHeaders => ParseError::TooLarge);
        from!(httparse::Error::Version => ParseError::Version);
    }
}
<|endoftext|>