<commit_before>use env_logger;
use std::env;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::sync::Mutex;
use std::thread;
use time;

use common::serialize as binary;
use common::socket::ReceiveSocket;
use common::stopwatch::TimerSet;
use common::terrain_block::{BLOCK_WIDTH, TEXTURE_WIDTH};

use client_recv_thread::apply_client_update;
use opencl_context::CL;
use server::Server;
use terrain::texture_generator::TerrainTextureGenerator;
use update_gaia::update_gaia;
use update_world::update_world;

// TODO: This is duplicated in the client. Fix that.
#[allow(missing_docs)]
trait TryRecv<T> {
  #[allow(missing_docs)]
  fn try_recv_opt(&self) -> Option<T>;
}

impl<T> TryRecv<T> for Receiver<T> where T: Send {
  #[inline(always)]
  fn try_recv_opt(&self) -> Option<T> {
    match self.try_recv() {
      Ok(msg) => Some(msg),
      Err(TryRecvError::Empty) => None,
      e => Some(e.unwrap()),
    }
  }
}

#[allow(missing_docs)]
trait MapToBool<T> {
  #[allow(missing_docs)]
  fn map_to_bool<F: FnOnce(T)>(self, f: F) -> bool;
}

impl<T> MapToBool<T> for Option<T> {
  #[inline(always)]
  fn map_to_bool<F: FnOnce(T)>(self, f: F) -> bool {
    match self {
      None => false,
      Some(t) => {
        f(t);
        true
      },
    }
  }
}

#[main]
fn main() {
  env_logger::init().unwrap();

  let mut args = env::args();
  args.next().unwrap();
  let listen_url
    = args.next().unwrap_or(String::from_str("ipc:///tmp/server.ipc"));
  assert!(args.next().is_none());

  info!("Listening on {}.", listen_url);

  let (listen_thread_send, listen_thread_recv) = channel();
  let (gaia_thread_send, gaia_thread_recv) = channel();

  let listen_thread_recv = Mutex::new(listen_thread_recv);
  let gaia_thread_recv = Mutex::new(gaia_thread_recv);

  let _listen_thread = {
    let listen_thread_send = listen_thread_send.clone();
    thread::scoped(move || {
      let mut socket = ReceiveSocket::new(listen_url.as_slice(), None);
      loop {
        let msg = socket.read();
        listen_thread_send.send(msg).unwrap();
      }
    })
  };

  let server = Server::new();
  let server = &server;

  // Add a thread that performs several actions repeatedly in a prioritized order:
  // Only if an action fails do we try the next action; otherwise, we restart the chain.
  macro_rules! in_series(
    ( $($action: expr,)* ) => {
      loop {
        $(
          if $action {
            continue
          }
        )*

        thread::yield_now();
      }
    };
  );

  let mut threads = Vec::new();

  {
    let gaia_thread_send = gaia_thread_send.clone();
    let listen_thread_recv = &listen_thread_recv;
    threads.push(thread::scoped(move || {
      let timers = TimerSet::new();
      let timers = &timers;

      let cl = unsafe {
        CL::new()
      };
      let cl = &cl;

      let texture_generators = [
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[0], BLOCK_WIDTH as u32),
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[1], BLOCK_WIDTH as u32),
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[2], BLOCK_WIDTH as u32),
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[3], BLOCK_WIDTH as u32),
      ];
      let texture_generators = &texture_generators;

      in_series!(
        {
          listen_thread_recv.lock().unwrap().try_recv_opt()
            .map_to_bool(|up| {
              let up = binary::decode(up.as_slice()).unwrap();
              apply_client_update(server, &mut |block| { gaia_thread_send.send(block).unwrap() }, up)
            })
        },
        {
          if server.update_timer.lock().unwrap().update(time::precise_time_ns()) > 0 {
            update_world(
              timers,
              server,
              &gaia_thread_send,
            );
            true
          } else {
            false
          }
        },
        {
          gaia_thread_recv.lock().unwrap().try_recv_opt()
            .map_to_bool(|up| {
              update_gaia(timers, server, texture_generators, cl, up)
            })
        },
      );
    }));
  }
}

#[test]
fn keep_bin_code_live() {
  let i = 0;
  if i == 1 {
    main();
  }
}
<commit_msg>Prioritize world updates over receiving packets from clients.<commit_after>use env_logger;
use std::env;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::sync::Mutex;
use std::thread;
use time;

use common::serialize as binary;
use common::socket::ReceiveSocket;
use common::stopwatch::TimerSet;
use common::terrain_block::{BLOCK_WIDTH, TEXTURE_WIDTH};

use client_recv_thread::apply_client_update;
use opencl_context::CL;
use server::Server;
use terrain::texture_generator::TerrainTextureGenerator;
use update_gaia::update_gaia;
use update_world::update_world;

// TODO: This is duplicated in the client. Fix that.
#[allow(missing_docs)]
trait TryRecv<T> {
  #[allow(missing_docs)]
  fn try_recv_opt(&self) -> Option<T>;
}

impl<T> TryRecv<T> for Receiver<T> where T: Send {
  #[inline(always)]
  fn try_recv_opt(&self) -> Option<T> {
    match self.try_recv() {
      Ok(msg) => Some(msg),
      Err(TryRecvError::Empty) => None,
      e => Some(e.unwrap()),
    }
  }
}

#[allow(missing_docs)]
trait MapToBool<T> {
  #[allow(missing_docs)]
  fn map_to_bool<F: FnOnce(T)>(self, f: F) -> bool;
}

impl<T> MapToBool<T> for Option<T> {
  #[inline(always)]
  fn map_to_bool<F: FnOnce(T)>(self, f: F) -> bool {
    match self {
      None => false,
      Some(t) => {
        f(t);
        true
      },
    }
  }
}

#[main]
fn main() {
  env_logger::init().unwrap();

  let mut args = env::args();
  args.next().unwrap();
  let listen_url
    = args.next().unwrap_or(String::from_str("ipc:///tmp/server.ipc"));
  assert!(args.next().is_none());

  info!("Listening on {}.", listen_url);

  let (listen_thread_send, listen_thread_recv) = channel();
  let (gaia_thread_send, gaia_thread_recv) = channel();

  let listen_thread_recv = Mutex::new(listen_thread_recv);
  let gaia_thread_recv = Mutex::new(gaia_thread_recv);

  let _listen_thread = {
    let listen_thread_send = listen_thread_send.clone();
    thread::scoped(move || {
      let mut socket = ReceiveSocket::new(listen_url.as_slice(), None);
      loop {
        let msg = socket.read();
        listen_thread_send.send(msg).unwrap();
      }
    })
  };

  let server = Server::new();
  let server = &server;

  // Add a thread that performs several actions repeatedly in a prioritized order:
  // Only if an action fails do we try the next action; otherwise, we restart the chain.
  macro_rules! in_series(
    ( $($action: expr,)* ) => {
      loop {
        $(
          if $action {
            continue
          }
        )*

        thread::yield_now();
      }
    };
  );

  let mut threads = Vec::new();

  {
    let gaia_thread_send = gaia_thread_send.clone();
    let listen_thread_recv = &listen_thread_recv;
    threads.push(thread::scoped(move || {
      let timers = TimerSet::new();
      let timers = &timers;

      let cl = unsafe {
        CL::new()
      };
      let cl = &cl;

      let texture_generators = [
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[0], BLOCK_WIDTH as u32),
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[1], BLOCK_WIDTH as u32),
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[2], BLOCK_WIDTH as u32),
          TerrainTextureGenerator::new(&cl, TEXTURE_WIDTH[3], BLOCK_WIDTH as u32),
      ];
      let texture_generators = &texture_generators;

      in_series!(
        {
          if server.update_timer.lock().unwrap().update(time::precise_time_ns()) > 0 {
            update_world(
              timers,
              server,
              &gaia_thread_send,
            );
            true
          } else {
            false
          }
        },
        {
          listen_thread_recv.lock().unwrap().try_recv_opt()
            .map_to_bool(|up| {
              let up = binary::decode(up.as_slice()).unwrap();
              apply_client_update(server, &mut |block| { gaia_thread_send.send(block).unwrap() }, up)
            })
        },
        {
          gaia_thread_recv.lock().unwrap().try_recv_opt()
            .map_to_bool(|up| {
              update_gaia(timers, server, texture_generators, cl, up)
            })
        },
      );
    }));
  }
}

#[test]
fn keep_bin_code_live() {
  let i = 0;
  if i == 1 {
    main();
  }
}
<|endoftext|>


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

use anyhow::Result;
use libra_types::{
    mempool_status::{MempoolStatus, MempoolStatusCode},
    vm_status::{StatusCode, StatusType},
};
use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Custom JSON RPC server error codes
/// Use ranges from -32000 to -32099 for internal error - see `https://www.jsonrpc.org/specification#error_object` for details
/// Use ranges from -32800 to -32899 for client errors got from Vm errors
/// Use ranges from -32900 to -32999 for client errors got from Mempool errors
pub enum ServerCode {
    DefaultServerError = -32000,

    // VM errors - see `vm_status.rs` for specs
    VmInvariantViolationError = -32001,
    VmExecutionError = -32002,
    VmUnknownError = -32003,
    VmValidationError = -32801,      // client error
    VmVerificationError = -32802,    // client error
    VmDeserializationError = -32803, // client error

    // Mempool errors - see `MempoolStatusCode` for specs
    MempoolIsFull = -32010,
    MempoolTooManyTransactions = -32011,
    MempoolVmError = -32012,
    MempoolUnknownError = -32013,
    MempoolInvalidSeqNumber = -32901, // client error
    MempoolInvalidUpdate = -32902,    // client error
}

/// JSON RPC server error codes for invalid request
pub enum InvalidRequestCode {
    InvalidRequest = -32600,
    MethodNotFound = -32601,
    InvalidParams = -32602,
    // -32603 is internal error
    InvalidFormat = -32604,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum ErrorData {
    StatusCode(StatusCode),
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JsonRpcError {
    pub code: i16,
    pub message: String,
    pub data: Option<ErrorData>,
}

impl std::error::Error for JsonRpcError {}

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

impl From<serde_json::error::Error> for JsonRpcError {
    fn from(err: serde_json::error::Error) -> Self {
        JsonRpcError::internal_error(err.to_string())
    }
}

impl From<anyhow::Error> for JsonRpcError {
    fn from(err: anyhow::Error) -> Self {
        JsonRpcError::internal_error(err.to_string())
    }
}

impl JsonRpcError {
    pub fn serialize(self) -> Value {
        serde_json::to_value(self).unwrap_or(Value::Null)
    }

    pub fn invalid_request() -> Self {
        Self::invalid_request_with_data(Option::None)
    }

    pub fn invalid_request_with_data(data: Option<ErrorData>) -> Self {
        Self {
            code: InvalidRequestCode::InvalidRequest as i16,
            message: "Invalid Request".to_string(),
            data,
        }
    }

    pub fn invalid_request_with_msg(msg: String) -> Self {
        Self {
            code: InvalidRequestCode::InvalidRequest as i16,
            message: format!("Invalid Request: {}", msg),
            data: None,
        }
    }

    pub fn invalid_format() -> Self {
        Self {
            code: InvalidRequestCode::InvalidFormat as i16,
            message: "Invalid request format".to_string(),
            data: None,
        }
    }

    pub fn invalid_params(data: Option<ErrorData>) -> Self {
        Self {
            code: InvalidRequestCode::InvalidParams as i16,
            message: "Invalid params".to_string(),
            data,
        }
    }

    pub fn invalid_params_size(msg: String) -> Self {
        Self {
            code: InvalidRequestCode::InvalidParams as i16,
            message: format!("Invalid params: {}", msg),
            data: None,
        }
    }

    pub fn invalid_param(index: usize, name: &str, type_info: &str) -> Self {
        Self {
            code: InvalidRequestCode::InvalidParams as i16,
            message: format!(
                "Invalid param {}(params[{}]): should be {}",
                name, index, type_info
            ),
            data: None,
        }
    }

    pub fn method_not_found() -> Self {
        Self {
            code: InvalidRequestCode::MethodNotFound as i16,
            message: "Method not found".to_string(),
            data: None,
        }
    }

    pub fn internal_error(message: String) -> Self {
        Self {
            code: ServerCode::DefaultServerError as i16,
            message: format!("Server error: {}", message),
            data: None,
        }
    }

    pub fn mempool_error(error: MempoolStatus) -> Result<Self> {
        let code = match error.code {
            MempoolStatusCode::InvalidSeqNumber => ServerCode::MempoolInvalidSeqNumber,
            MempoolStatusCode::MempoolIsFull => ServerCode::MempoolIsFull,
            MempoolStatusCode::TooManyTransactions => ServerCode::MempoolTooManyTransactions,
            MempoolStatusCode::InvalidUpdate => ServerCode::MempoolInvalidUpdate,
            MempoolStatusCode::VmError => ServerCode::MempoolVmError,
            MempoolStatusCode::UnknownStatus => ServerCode::MempoolUnknownError,
            MempoolStatusCode::Accepted => {
                return Err(anyhow::format_err!(
                    "[JSON RPC] cannot create mempool error for mempool accepted status"
                ))
            }
        };

        Ok(Self {
            code: code as i16,
            message: format!(
                "Server error: Mempool submission error: {:?}",
                error.message
            ),
            data: None,
        })
    }

    pub fn vm_status(error: StatusCode) -> Self {
        // map VM status to custom server code
        let vm_status_type = error.status_type();
        let code = match vm_status_type {
            StatusType::Validation => ServerCode::VmValidationError,
            StatusType::Verification => ServerCode::VmVerificationError,
            StatusType::InvariantViolation => ServerCode::VmInvariantViolationError,
            StatusType::Deserialization => ServerCode::VmDeserializationError,
            StatusType::Execution => ServerCode::VmExecutionError,
            StatusType::Unknown => ServerCode::VmUnknownError,
        };

        Self {
            code: code as i16,
            message: format!("Server error: VM {} error: {:?}", vm_status_type, error),
            data: Some(ErrorData::StatusCode(error)),
        }
    }

    pub fn as_status_code(&self) -> Option<StatusCode> {
        if let Some(ErrorData::StatusCode(data)) = &self.data {
            return Some(*data);
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use crate::errors::{JsonRpcError, ServerCode};
    use libra_types::{
        mempool_status::{MempoolStatus, MempoolStatusCode},
        vm_status::StatusCode,
    };

    #[test]
    fn test_vm_status() {
        assert_map_vm_code(
            StatusCode::UNKNOWN_VALIDATION_STATUS,
            ServerCode::VmValidationError,
        );

        let err = JsonRpcError::vm_status(StatusCode::UNKNOWN_VERIFICATION_ERROR);
        assert_eq!(err.code, ServerCode::VmVerificationError as i16);
        assert_map_vm_code(
            StatusCode::UNKNOWN_VERIFICATION_ERROR,
            ServerCode::VmVerificationError,
        );

        assert_map_vm_code(
            StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR,
            ServerCode::VmInvariantViolationError,
        );

        assert_map_vm_code(
            StatusCode::UNKNOWN_BINARY_ERROR,
            ServerCode::VmDeserializationError,
        );
        assert_map_vm_code(
            StatusCode::UNKNOWN_RUNTIME_STATUS,
            ServerCode::VmExecutionError,
        );
        assert_map_vm_code(StatusCode::UNKNOWN_STATUS, ServerCode::VmUnknownError);
    }

    fn assert_map_vm_code(from: StatusCode, to: ServerCode) {
        let err = JsonRpcError::vm_status(from);
        assert_eq!(err.code, to as i16);
    }

    #[test]
    fn test_mempool_error() {
        let err = JsonRpcError::mempool_error(MempoolStatus {
            code: MempoolStatusCode::Accepted,
            message: "error msg".to_string(),
        });
        assert!(err.is_err());

        assert_map_code(
            MempoolStatusCode::InvalidSeqNumber,
            ServerCode::MempoolInvalidSeqNumber,
        );
        assert_map_code(MempoolStatusCode::MempoolIsFull, ServerCode::MempoolIsFull);
        assert_map_code(
            MempoolStatusCode::TooManyTransactions,
            ServerCode::MempoolTooManyTransactions,
        );
        assert_map_code(
            MempoolStatusCode::InvalidUpdate,
            ServerCode::MempoolInvalidUpdate,
        );
        assert_map_code(MempoolStatusCode::VmError, ServerCode::MempoolVmError);
        assert_map_code(
            MempoolStatusCode::UnknownStatus,
            ServerCode::MempoolUnknownError,
        );
    }

    fn assert_map_code(from: MempoolStatusCode, to: ServerCode) {
        let err = JsonRpcError::mempool_error(MempoolStatus {
            code: from,
            message: "error msg".to_string(),
        })
        .unwrap();
        assert_eq!(err.code, to as i16);
    }
}
<commit_msg>Revert "[json-rpc] mark client side error code correctly"<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use libra_types::{
    mempool_status::{MempoolStatus, MempoolStatusCode},
    vm_status::{StatusCode, StatusType},
};
use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Custom JSON RPC server error codes
/// Ranges from -32000 to -32099 - see `https://www.jsonrpc.org/specification#error_object` for details
pub enum ServerCode {
    DefaultServerError = -32000,

    // VM errors - see `vm_status.rs` for specs
    VmValidationError = -32001,
    VmVerificationError = -32002,
    VmInvariantViolationError = -32003,
    VmDeserializationError = -32004,
    VmExecutionError = -32005,
    VmUnknownError = -32006,

    // Mempool errors - see `MempoolStatusCode` for specs
    MempoolInvalidSeqNumber = -32007,
    MempoolIsFull = -32008,
    MempoolTooManyTransactions = -32009,
    MempoolInvalidUpdate = -32010,
    MempoolVmError = -32011,
    MempoolUnknownError = -32012,
}

/// JSON RPC server error codes for invalid request
pub enum InvalidRequestCode {
    InvalidRequest = -32600,
    MethodNotFound = -32601,
    InvalidParams = -32602,
    // -32603 is internal error
    InvalidFormat = -32604,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum ErrorData {
    StatusCode(StatusCode),
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JsonRpcError {
    pub code: i16,
    pub message: String,
    pub data: Option<ErrorData>,
}

impl std::error::Error for JsonRpcError {}

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

impl From<serde_json::error::Error> for JsonRpcError {
    fn from(err: serde_json::error::Error) -> Self {
        JsonRpcError::internal_error(err.to_string())
    }
}

impl From<anyhow::Error> for JsonRpcError {
    fn from(err: anyhow::Error) -> Self {
        JsonRpcError::internal_error(err.to_string())
    }
}

impl JsonRpcError {
    pub fn serialize(self) -> Value {
        serde_json::to_value(self).unwrap_or(Value::Null)
    }

    pub fn invalid_request() -> Self {
        Self::invalid_request_with_data(Option::None)
    }

    pub fn invalid_request_with_data(data: Option<ErrorData>) -> Self {
        Self {
            code: InvalidRequestCode::InvalidRequest as i16,
            message: "Invalid Request".to_string(),
            data,
        }
    }

    pub fn invalid_request_with_msg(msg: String) -> Self {
        Self {
            code: InvalidRequestCode::InvalidRequest as i16,
            message: format!("Invalid Request: {}", msg),
            data: None,
        }
    }

    pub fn invalid_format() -> Self {
        Self {
            code: InvalidRequestCode::InvalidFormat as i16,
            message: "Invalid request format".to_string(),
            data: None,
        }
    }

    pub fn invalid_params(data: Option<ErrorData>) -> Self {
        Self {
            code: InvalidRequestCode::InvalidParams as i16,
            message: "Invalid params".to_string(),
            data,
        }
    }

    pub fn invalid_params_size(msg: String) -> Self {
        Self {
            code: InvalidRequestCode::InvalidParams as i16,
            message: format!("Invalid params: {}", msg),
            data: None,
        }
    }

    pub fn invalid_param(index: usize, name: &str, type_info: &str) -> Self {
        Self {
            code: InvalidRequestCode::InvalidParams as i16,
            message: format!(
                "Invalid param {}(params[{}]): should be {}",
                name, index, type_info
            ),
            data: None,
        }
    }

    pub fn method_not_found() -> Self {
        Self {
            code: InvalidRequestCode::MethodNotFound as i16,
            message: "Method not found".to_string(),
            data: None,
        }
    }

    pub fn internal_error(message: String) -> Self {
        Self {
            code: ServerCode::DefaultServerError as i16,
            message: format!("Server error: {}", message),
            data: None,
        }
    }

    pub fn mempool_error(error: MempoolStatus) -> Result<Self> {
        let code = match error.code {
            MempoolStatusCode::InvalidSeqNumber => ServerCode::MempoolInvalidSeqNumber,
            MempoolStatusCode::MempoolIsFull => ServerCode::MempoolIsFull,
            MempoolStatusCode::TooManyTransactions => ServerCode::MempoolTooManyTransactions,
            MempoolStatusCode::InvalidUpdate => ServerCode::MempoolInvalidUpdate,
            MempoolStatusCode::VmError => ServerCode::MempoolVmError,
            MempoolStatusCode::UnknownStatus => ServerCode::MempoolUnknownError,
            MempoolStatusCode::Accepted => {
                return Err(anyhow::format_err!(
                    "[JSON RPC] cannot create mempool error for mempool accepted status"
                ))
            }
        };

        Ok(Self {
            code: code as i16,
            message: format!(
                "Server error: Mempool submission error: {:?}",
                error.message
            ),
            data: None,
        })
    }

    pub fn vm_status(error: StatusCode) -> Self {
        // map VM status to custom server code
        let vm_status_type = error.status_type();
        let code = match vm_status_type {
            StatusType::Validation => ServerCode::VmValidationError,
            StatusType::Verification => ServerCode::VmVerificationError,
            StatusType::InvariantViolation => ServerCode::VmInvariantViolationError,
            StatusType::Deserialization => ServerCode::VmDeserializationError,
            StatusType::Execution => ServerCode::VmExecutionError,
            StatusType::Unknown => ServerCode::VmUnknownError,
        };

        Self {
            code: code as i16,
            message: format!("Server error: VM {} error: {:?}", vm_status_type, error),
            data: Some(ErrorData::StatusCode(error)),
        }
    }

    pub fn as_status_code(&self) -> Option<StatusCode> {
        if let Some(ErrorData::StatusCode(data)) = &self.data {
            return Some(*data);
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use crate::errors::{JsonRpcError, ServerCode};
    use libra_types::{
        mempool_status::{MempoolStatus, MempoolStatusCode},
        vm_status::StatusCode,
    };

    #[test]
    fn test_vm_status() {
        assert_map_vm_code(
            StatusCode::UNKNOWN_VALIDATION_STATUS,
            ServerCode::VmValidationError,
        );

        let err = JsonRpcError::vm_status(StatusCode::UNKNOWN_VERIFICATION_ERROR);
        assert_eq!(err.code, ServerCode::VmVerificationError as i16);
        assert_map_vm_code(
            StatusCode::UNKNOWN_VERIFICATION_ERROR,
            ServerCode::VmVerificationError,
        );

        assert_map_vm_code(
            StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR,
            ServerCode::VmInvariantViolationError,
        );

        assert_map_vm_code(
            StatusCode::UNKNOWN_BINARY_ERROR,
            ServerCode::VmDeserializationError,
        );
        assert_map_vm_code(
            StatusCode::UNKNOWN_RUNTIME_STATUS,
            ServerCode::VmExecutionError,
        );
        assert_map_vm_code(StatusCode::UNKNOWN_STATUS, ServerCode::VmUnknownError);
    }

    fn assert_map_vm_code(from: StatusCode, to: ServerCode) {
        let err = JsonRpcError::vm_status(from);
        assert_eq!(err.code, to as i16);
    }

    #[test]
    fn test_mempool_error() {
        let err = JsonRpcError::mempool_error(MempoolStatus {
            code: MempoolStatusCode::Accepted,
            message: "error msg".to_string(),
        });
        assert!(err.is_err());

        assert_map_code(
            MempoolStatusCode::InvalidSeqNumber,
            ServerCode::MempoolInvalidSeqNumber,
        );
        assert_map_code(MempoolStatusCode::MempoolIsFull, ServerCode::MempoolIsFull);
        assert_map_code(
            MempoolStatusCode::TooManyTransactions,
            ServerCode::MempoolTooManyTransactions,
        );
        assert_map_code(
            MempoolStatusCode::InvalidUpdate,
            ServerCode::MempoolInvalidUpdate,
        );
        assert_map_code(MempoolStatusCode::VmError, ServerCode::MempoolVmError);
        assert_map_code(
            MempoolStatusCode::UnknownStatus,
            ServerCode::MempoolUnknownError,
        );
    }

    fn assert_map_code(from: MempoolStatusCode, to: ServerCode) {
        let err = JsonRpcError::mempool_error(MempoolStatus {
            code: from,
            message: "error msg".to_string(),
        })
        .unwrap();
        assert_eq!(err.code, to as i16);
    }
}
<|endoftext|>


<commit_before>// Implements the `zakopane checksum` subcommand.

use crate::structs::ZakopaneError;

const MAX_TASKS: usize = 8;
type ChecksumResult = Result<String, ZakopaneError>;

struct ChecksumTaskManager {
    // Non-associative container enumerating paths and checksums.
    sums: std::vec::Vec<(String, String)>,

    // Map of outstanding checksum tasks.
    // *    Keys: absolute paths being checksummed
    // *    Values: tokio JoinHandles for checksum tasks
    tasks: std::collections::HashMap<String, tokio::task::JoinHandle<()>>,

    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
    receiver: tokio::sync::mpsc::Receiver<ChecksumResult>,
}

async fn do_checksum(path: std::path::PathBuf) {
    todo!()
}

impl ChecksumTaskManager {
    pub fn new() -> Self {
        let (sender, receiver) = tokio::sync::mpsc::channel(MAX_TASKS);
        Self {
            sums: Default::default(),
            tasks: Default::default(),
            sender: sender,
            receiver: receiver,
        }
    }

    pub fn spawn_task(&mut self, path: std::path::PathBuf) {
        assert!(
            self.tasks.len() < MAX_TASKS,
            "attempted to spawn too many tasks"
        );
        self.tasks.insert(
            String::from(path.to_str().unwrap()),
            tokio::spawn(do_checksum(path)),
        );
    }
}

async fn checksum_impl() -> ChecksumResult {
    // *    Walk the target path.
    // *    If we can, then spawn a task, providing the current path
    //      in the walk and a cloned transmitter.
    // *    Call `poll_recv()` on the receiver repeatedly, updating
    //      our checksum map and `join()`ing the completed tasks.
    todo!()
}

#[allow(dead_code)]
fn checksum() -> ChecksumResult {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(checksum_impl())
}
<commit_msg>checksum: Clone sender channel to `do_checksum()`<commit_after>// Implements the `zakopane checksum` subcommand.

use crate::structs::ZakopaneError;

const MAX_TASKS: usize = 8;
type ChecksumResult = Result<String, ZakopaneError>;

struct ChecksumTaskManager {
    // Non-associative container enumerating paths and checksums.
    sums: std::vec::Vec<(String, String)>,

    // Map of outstanding checksum tasks.
    // *    Keys: absolute paths being checksummed
    // *    Values: tokio JoinHandles for checksum tasks
    tasks: std::collections::HashMap<String, tokio::task::JoinHandle<()>>,

    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
    receiver: tokio::sync::mpsc::Receiver<ChecksumResult>,
}

async fn do_checksum(path: std::path::PathBuf, sender: tokio::sync::mpsc::Sender<ChecksumResult>) {
    todo!()
}

impl ChecksumTaskManager {
    pub fn new() -> Self {
        let (sender, receiver) = tokio::sync::mpsc::channel(MAX_TASKS);
        Self {
            sums: Default::default(),
            tasks: Default::default(),
            sender: sender,
            receiver: receiver,
        }
    }

    pub fn spawn_task(&mut self, path: std::path::PathBuf) {
        assert!(
            self.tasks.len() < MAX_TASKS,
            "attempted to spawn too many tasks"
        );
        self.tasks.insert(
            String::from(path.to_str().unwrap()),
            tokio::spawn(do_checksum(path, self.sender.clone())),
        );
    }
}

async fn checksum_impl() -> ChecksumResult {
    // *    Walk the target path.
    // *    If we can, then spawn a task, providing the current path
    //      in the walk and a cloned transmitter.
    // *    Call `poll_recv()` on the receiver repeatedly, updating
    //      our checksum map and `join()`ing the completed tasks.
    todo!()
}

#[allow(dead_code)]
fn checksum() -> ChecksumResult {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(checksum_impl())
}
<|endoftext|>


<commit_before>use std::mem;
fn main() {

}

fn cityhash32(mut s: &[u8], len: usize) -> u32 { // mut s: &[u8]
  if len <= 24 {
  	return if len <= 12 {
        if len <= 4 {
          hash32Len0to4(s, len)
        } else {
          hash32_len_5_to_12(s, len)
        }
      } else {
        hash32_len_13_to_24(s, len)
    }
  }

  // len > 32
  let mut h = len as u32;
  let mut g = (len as u32).wrapping_mul(C1);
  let mut f = g;

  let mut a0 = rotate32(fetch32(&s[len-4..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a1 = rotate32(fetch32(&s[len-8..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a2 = rotate32(fetch32(&s[len-16..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a3 = rotate32(fetch32(&s[len-12..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a4 = rotate32(fetch32(&s[len-20..]).wrapping_mul(C1), 17).wrapping_mul(C2);

  h ^= a0;
  h = rotate32(h, 19);
  h = h.wrapping_mul(5).wrapping_add(0xe6546b64);
  h ^= a2;
  h = rotate32(h, 19);
  h = h.wrapping_mul(5).wrapping_add(0xe6546b64);
  g ^= a1;
  g = rotate32(g, 19);
  g = g.wrapping_mul(5).wrapping_add(0xe6546b64);
  g ^= a3;
  g = rotate32(g, 19);
  g = g.wrapping_mul(5).wrapping_add(0xe6546b64);
  f = f.wrapping_add(a4);
  f = rotate32(f, 19).wrapping_add(113);
  f = f.wrapping_mul(5).wrapping_add(0xe6546b64);

  let mut iters = ((len - 1) / 20) as u64;
  while iters > 0 {
    let a0 = rotate32(fetch32(&s[..]).wrapping_mul(C1), 17).wrapping_mul(C2);
    let a1 = fetch32(&s[4..]);
    let a2 = rotate32(fetch32(&s[8..]).wrapping_mul(C1), 17).wrapping_mul(C2);
    let a3 = rotate32(fetch32(&s[12..]).wrapping_mul(C1), 17).wrapping_mul(C2);
    let a4 = fetch32(&s[16..]);
    h ^= a0;
    h = rotate32(h, 18);
    h = (h * 5).wrapping_add(0xe6546b64);
    f += a1;
    f = rotate32(f, 19);
    f = f.wrapping_mul(C1);
    g += a2;
    g = rotate32(g, 18);
    g = (g * 5).wrapping_add(0xe6546b64);
    h ^= a3 + a1;
    h = rotate32(h, 19);
    h = (h * 5).wrapping_add(0xe6546b64);
    g ^= a4;
    g = bswap32(g) * 5;
    h += a4 * 5;
    h = bswap32(h);
    f += a0;
    //#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)
    //PERMUTE3(f, h, g);
    mem::swap(&mut h, &mut f);

    mem::swap(&mut g, &mut f);
    s = &s[20..];
    iters -= 1;
  }

  g = rotate32(g, 11) * C1;
  g = rotate32(g, 17) * C1;
  f = rotate32(f, 11) * C1;
  f = rotate32(f, 17) * C1;
  h = rotate32(h + g, 19);
  h = h * 5 + 0xe6546b64;
  h = rotate32(h, 17) * C1;
  h = rotate32(h + f, 19);
  h = h * 5 + 0xe6546b64;
  h = rotate32(h, 17) * C1;
  return h;
}

fn hash32Len0to4(s: &[u8], len: usize) -> u32 {
  let mut b: u32 = 0;
  let mut c: u32 = 9;
  for i in 0..len {
    let v: u8 = s[i];
    b = b.wrapping_mul(C1) + v as u32;
    c ^= b;
  }
  return fmix(mur(b, mur(len as u32, c)));
}

pub fn fetch32(p: &[u8]) -> u32 {
    (p[0] as u32) | (p[1] as u32) << 8 | (p[2] as u32) << 16 | (p[3] as u32) << 24
}

// rotate32 is a bitwise rotate
pub fn rotate32(val: u32, shift: u32) -> u32 {
    if shift == 0 {
        return val;
    }
    return val >> shift | val << (32 - shift)
}

// Some primes between 2^63 and 2^64 for various uses.
pub const K0: u64 = 0xc3a5c85c97cb3127;
pub const K1: u64 = 0xb492b66fbe98f273;
pub const K2: u64 = 0x9ae16a3b2f90404f;

// Magic numbers for 32-bit hashing.  Copied from Murmur3.
pub const C1: u32 = 0xcc9e2d51;
pub const C2: u32 = 0x1b873593;

// fmix is a 32-bit to 32-bit integer hash copied from Murmur3.
pub fn fmix(mut h: u32) -> u32 {
    h ^= h >> 16;
    h = h.wrapping_mul(0x85ebca6b);
    h ^= h >> 13;
    h = h.wrapping_mul(0xc2b2ae35);
    h ^= h >> 16;
    return h;
}

// Mur is a helper from Murmur3 for combining two 32-bit values.
pub fn mur(mut a: u32, mut h: u32) -> u32 {
    a = a.wrapping_mul(C1);
    a = rotate32(a, 17);
    a = a.wrapping_mul(C2);
    h ^= a;
    h = rotate32(h, 19);
    return h.wrapping_mul(5).wrapping_add(0xe6546b64);
}

fn hash32_len_5_to_12(s: &[u8], len: usize) -> u32 {
  let mut a = len as u32;
  let mut b = len as u32 * 5;
  let mut c: u32 = 9;
  let d: u32 = b;
  a += fetch32(&s[0..]);
  b += fetch32(&s[len-4..]);
  c += fetch32(&s[((len >> 1) & 4)..]);
  return fmix(mur(c, mur(b, mur(a, d))));
}

fn hash32_len_13_to_24(s: &[u8], len: usize) -> u32 {
  let a = fetch32(&s[-4+(len>>1 as u64)..]);
  let b = fetch32(&s[4..]);
  let c = fetch32(&s[len-8..]);
  let d = fetch32(&s[len>>1..]);
  let e = fetch32(&s[0..]);
  let f = fetch32(&s[len-4..]);
  let h = len as u32;

  return fmix(mur(f, mur(e, mur(d, mur(c, mur(b, mur(a, h)))))));
}

pub fn bswap32(x: u32) -> u32 {
    return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
        ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000)
}
<commit_msg>Removed public modifier from functions.<commit_after>use std::mem;
fn main() {

}

pub fn cityhash32(mut s: &[u8], len: usize) -> u32 { // mut s: &[u8]
  if len <= 24 {
  	return if len <= 12 {
        if len <= 4 {
          hash32Len0to4(s, len)
        } else {
          hash32_len_5_to_12(s, len)
        }
      } else {
        hash32_len_13_to_24(s, len)
    }
  }

  // len > 32
  let mut h = len as u32;
  let mut g = (len as u32).wrapping_mul(C1);
  let mut f = g;

  let mut a0 = rotate32(fetch32(&s[len-4..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a1 = rotate32(fetch32(&s[len-8..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a2 = rotate32(fetch32(&s[len-16..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a3 = rotate32(fetch32(&s[len-12..]).wrapping_mul(C1), 17).wrapping_mul(C2);
  let mut a4 = rotate32(fetch32(&s[len-20..]).wrapping_mul(C1), 17).wrapping_mul(C2);

  h ^= a0;
  h = rotate32(h, 19);
  h = h.wrapping_mul(5).wrapping_add(0xe6546b64);
  h ^= a2;
  h = rotate32(h, 19);
  h = h.wrapping_mul(5).wrapping_add(0xe6546b64);
  g ^= a1;
  g = rotate32(g, 19);
  g = g.wrapping_mul(5).wrapping_add(0xe6546b64);
  g ^= a3;
  g = rotate32(g, 19);
  g = g.wrapping_mul(5).wrapping_add(0xe6546b64);
  f = f.wrapping_add(a4);
  f = rotate32(f, 19).wrapping_add(113);
  f = f.wrapping_mul(5).wrapping_add(0xe6546b64);

  let mut iters = ((len - 1) / 20) as u64;
  while iters > 0 {
    let a0 = rotate32(fetch32(&s[..]).wrapping_mul(C1), 17).wrapping_mul(C2);
    let a1 = fetch32(&s[4..]);
    let a2 = rotate32(fetch32(&s[8..]).wrapping_mul(C1), 17).wrapping_mul(C2);
    let a3 = rotate32(fetch32(&s[12..]).wrapping_mul(C1), 17).wrapping_mul(C2);
    let a4 = fetch32(&s[16..]);
    h ^= a0;
    h = rotate32(h, 18);
    h = (h * 5).wrapping_add(0xe6546b64);
    f += a1;
    f = rotate32(f, 19);
    f = f.wrapping_mul(C1);
    g += a2;
    g = rotate32(g, 18);
    g = (g * 5).wrapping_add(0xe6546b64);
    h ^= a3 + a1;
    h = rotate32(h, 19);
    h = (h * 5).wrapping_add(0xe6546b64);
    g ^= a4;
    g = bswap32(g) * 5;
    h += a4 * 5;
    h = bswap32(h);
    f += a0;
    //#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)
    //PERMUTE3(f, h, g);
    mem::swap(&mut h, &mut f);

    mem::swap(&mut g, &mut f);
    s = &s[20..];
    iters -= 1;
  }

  g = rotate32(g, 11) * C1;
  g = rotate32(g, 17) * C1;
  f = rotate32(f, 11) * C1;
  f = rotate32(f, 17) * C1;
  h = rotate32(h + g, 19);
  h = h * 5 + 0xe6546b64;
  h = rotate32(h, 17) * C1;
  h = rotate32(h + f, 19);
  h = h * 5 + 0xe6546b64;
  h = rotate32(h, 17) * C1;
  return h;
}

fn hash32Len0to4(s: &[u8], len: usize) -> u32 {
  let mut b: u32 = 0;
  let mut c: u32 = 9;
  for i in 0..len {
    let v: u8 = s[i];
    b = b.wrapping_mul(C1) + v as u32;
    c ^= b;
  }
  return fmix(mur(b, mur(len as u32, c)));
}

fn fetch32(p: &[u8]) -> u32 {
    (p[0] as u32) | (p[1] as u32) << 8 | (p[2] as u32) << 16 | (p[3] as u32) << 24
}

// rotate32 is a bitwise rotate
fn rotate32(val: u32, shift: u32) -> u32 {
    if shift == 0 {
        return val;
    }
    return val >> shift | val << (32 - shift)
}

// Some primes between 2^63 and 2^64 for various uses.
pub const K0: u64 = 0xc3a5c85c97cb3127;
pub const K1: u64 = 0xb492b66fbe98f273;
pub const K2: u64 = 0x9ae16a3b2f90404f;

// Magic numbers for 32-bit hashing.  Copied from Murmur3.
pub const C1: u32 = 0xcc9e2d51;
pub const C2: u32 = 0x1b873593;

// fmix is a 32-bit to 32-bit integer hash copied from Murmur3.
fn fmix(mut h: u32) -> u32 {
    h ^= h >> 16;
    h = h.wrapping_mul(0x85ebca6b);
    h ^= h >> 13;
    h = h.wrapping_mul(0xc2b2ae35);
    h ^= h >> 16;
    return h;
}

// Mur is a helper from Murmur3 for combining two 32-bit values.
fn mur(mut a: u32, mut h: u32) -> u32 {
    a = a.wrapping_mul(C1);
    a = rotate32(a, 17);
    a = a.wrapping_mul(C2);
    h ^= a;
    h = rotate32(h, 19);
    return h.wrapping_mul(5).wrapping_add(0xe6546b64);
}

fn hash32_len_5_to_12(s: &[u8], len: usize) -> u32 {
  let mut a = len as u32;
  let mut b = len as u32 * 5;
  let mut c: u32 = 9;
  let d: u32 = b;
  a += fetch32(&s[0..]);
  b += fetch32(&s[len-4..]);
  c += fetch32(&s[((len >> 1) & 4)..]);
  return fmix(mur(c, mur(b, mur(a, d))));
}

fn hash32_len_13_to_24(s: &[u8], len: usize) -> u32 {
  let a = fetch32(&s[-4+(len>>1 as u64)..]);
  let b = fetch32(&s[4..]);
  let c = fetch32(&s[len-8..]);
  let d = fetch32(&s[len>>1..]);
  let e = fetch32(&s[0..]);
  let f = fetch32(&s[len-4..]);
  let h = len as u32;

  return fmix(mur(f, mur(e, mur(d, mur(c, mur(b, mur(a, h)))))));
}

fn bswap32(x: u32) -> u32 {
    return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
        ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000)
}
<|endoftext|>


<commit_before>pub static RUSTUP_HELP: &str = r"DISCUSSION:
    rustup installs The Rust Programming Language from the official
    release channels, enabling you to easily switch between stable,
    beta, and nightly compilers and keep them updated. It makes
    cross-compiling simpler with binary builds of the standard library
    for common platforms.

    If you are new to Rust consider running `rustup doc --book` to
    learn Rust.";

pub static SHOW_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain and the version of `rustc`.

    If the active toolchain has installed support for additional
    compilation targets, then they are listed as well.

    If there are multiple toolchains installed then all installed
    toolchains are listed as well.";

pub static SHOW_ACTIVE_TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain.

    This is useful for figuring out the active tool chain from
    scripts.

    You should use `rustc --print sysroot` to get the sysroot, or
    `rustc --version` to get the toolchain version.";

pub static UPDATE_HELP: &str = r"DISCUSSION:
    With no toolchain specified, the `update` command updates each of
    the installed toolchains from the official release channels, then
    updates rustup itself.

    If given a toolchain argument then `update` updates that
    toolchain, the same as `rustup toolchain install`.";

pub static INSTALL_HELP: &str = r"DISCUSSION:
    Installs a specific rust toolchain.

    The 'install' command is an alias for 'rustup update <toolchain>'.";

pub static DEFAULT_HELP: &str = r"DISCUSSION:
    Sets the default toolchain to the one specified. If the toolchain
    is not already installed then it is installed first.";

pub static TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Many `rustup` commands deal with *toolchains*, a single
    installation of the Rust compiler. `rustup` supports multiple
    types of toolchains. The most basic track the official release
    channels: 'stable', 'beta' and 'nightly'; but `rustup` can also
    install toolchains from the official archives, for alternate host
    platforms, and from local builds.

    Standard release channel toolchain names have the following form:

        <channel>[-<date>][-<host>]

        <channel>       = stable|beta|nightly|<version>
        <date>          = YYYY-MM-DD
        <host>          = <target-triple>

    'channel' is either a named release channel or an explicit version
    number, such as '1.8.0'. Channel names can be optionally appended
    with an archive date, as in 'nightly-2017-05-09', in which case
    the toolchain is downloaded from the archive for that date.

    The host may be specified as a target triple. This is most useful
    for installing a 32-bit compiler on a 64-bit platform, or for
    installing the [MSVC-based toolchain] on Windows. For example:

        $ rustup toolchain install stable-x86_64-pc-windows-msvc

    For convenience, omitted elements of the target triple will be
    inferred, so the above could be written:

        $ rustup toolchain install stable-msvc

    The `rustup default` command may be used to both install and set
    the desired toolchain as default in a single command:

        $ rustup default stable-msvc

    rustup can also manage symlinked local toolchain builds, which are
    often used for developing Rust itself. For more information see
    `rustup toolchain help link`.";

pub static TOOLCHAIN_LINK_HELP: &str = r"DISCUSSION:
    'toolchain' is the custom name to be assigned to the new toolchain.
    Any name is permitted as long as it does not fully match an initial
    substring of a standard release channel. For example, you can use
    the names 'latest' or '2017-04-01' but you cannot use 'stable' or
    'beta-i686' or 'nightly-x86_64-unknown-linux-gnu'.

    'path' specifies the directory where the binaries and libraries for
    the custom toolchain can be found. For example, when used for
    development of Rust itself, toolchains can be linked directly out of
    the build directory. After building, you can test out different
    compiler versions as follows:

        $ rustup toolchain link latest-stage1 build/x86_64-unknown-linux-gnu/stage1
        $ rustup override set latest-stage1

    If you now compile a crate in the current directory, the custom
    toolchain 'latest-stage1' will be used.";

pub static OVERRIDE_HELP: &str = r"DISCUSSION:
    Overrides configure rustup to use a specific toolchain when
    running in a specific directory.

    Directories can be assigned their own Rust toolchain with `rustup
    override`. When a directory has an override then any time `rustc`
    or `cargo` is run inside that directory, or one of its child
    directories, the override toolchain will be invoked.

    To pin to a specific nightly:

        $ rustup override set nightly-2014-12-18

    Or a specific stable release:

        $ rustup override set 1.0.0

    To see the active toolchain use `rustup show`. To remove the
    override and use the default toolchain again, `rustup override
    unset`.";

pub static OVERRIDE_UNSET_HELP: &str = r"DISCUSSION:
    If `--path` argument is present, removes the override toolchain
    for the specified directory. If `--nonexistent` argument is
    present, removes the override toolchain for all nonexistent
    directories. Otherwise, removes the override toolchain for the
    current directory.";

pub static RUN_HELP: &str = r"DISCUSSION:
    Configures an environment to use the given toolchain and then runs
    the specified program. The command may be any program, not just
    rustc or cargo. This can be used for testing arbitrary toolchains
    without setting an override.

    Commands explicitly proxied by `rustup` (such as `rustc` and
    `cargo`) also have a shorthand for this available. The toolchain
    can be set by using `+toolchain` as the first argument. These are
    equivalent:

        $ cargo +nightly build

        $ rustup run nightly cargo build";

pub static DOC_HELP: &str = r"DISCUSSION:
    Opens the documentation for the currently active toolchain with
    the default browser.

    By default, it opens the documentation index. Use the various
    flags to open specific pieces of documentation.";

pub static COMPLETIONS_HELP: &str =
r"DISCUSSION:
    Enable tab completion for Bash, Fish, Zsh, or PowerShell
    The script is output on `stdout`, allowing one to re-direct the
    output to the file of their choosing. Where you place the file
    will depend on which shell, and which operating system you are
    using. Your particular configuration may also determine where
    these scripts need to be placed.

    Here are some common set ups for the three supported shells under
    Unix and similar operating systems (such as GNU/Linux).

    BASH:

    Completion files are commonly stored in `/etc/bash_completion.d/` for
    system-wide commands, but can be stored in
    `~/.local/share/bash-completion/completions` for user-specific commands.
    Run the command:

        $ mkdir -p ~/.local/share/bash-completion/completions
        $ rustup completions bash >> ~/.local/share/bash-completion/completions/rustup

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take affect.

    BASH (macOS/Homebrew):

    Homebrew stores bash completion files within the Homebrew directory.
    With the `bash-completion` brew formula installed, run the command:

        $ mkdir -p $(brew --prefix)/etc/bash_completion.d
        $ rustup completions bash > $(brew --prefix)/etc/bash_completion.d/rustup.bash-completion

    FISH:

    Fish completion files are commonly stored in
    `$HOME/.config/fish/completions`. Run the command:

        $ mkdir -p ~/.config/fish/completions
        $ rustup completions fish > ~/.config/fish/completions/rustup.fish

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take affect.

    ZSH:

    ZSH completions are commonly stored in any directory listed in
    your `$fpath` variable. To use these completions, you must either
    add the generated script to one of those directories, or add your
    own to this list.

    Adding a custom directory is often the safest bet if you are
    unsure of which directory to use. First create the directory; for
    this example we'll create a hidden directory inside our `$HOME`
    directory:

        $ mkdir ~/.zfunc

    Then add the following lines to your `.zshrc` just before
    `compinit`:

        fpath+=~/.zfunc

    Now you can install the completions script using the following
    command:

        $ rustup completions zsh > ~/.zfunc/_rustup

    You must then either log out and log back in, or simply run

        $ exec zsh

    for the new completions to take affect.

    CUSTOM LOCATIONS:

    Alternatively, you could save these files to the place of your
    choosing, such as a custom directory inside your $HOME. Doing so
    will require you to add the proper directives, such as `source`ing
    inside your login script. Consult your shells documentation for
    how to add such directives.

    POWERSHELL:

    The powershell completion scripts require PowerShell v5.0+ (which
    comes Windows 10, but can be downloaded separately for windows 7
    or 8.1).

    First, check if a profile has already been set

        PS C:\> Test-Path $profile

    If the above command returns `False` run the following

        PS C:\> New-Item -path $profile -type file -force

    Now open the file provided by `$profile` (if you used the
    `New-Item` command it will be
    `${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`

    Next, we either save the completions file into our profile, or
    into a separate file and source it inside our profile. To save the
    completions into our profile simply use

        PS C:\> rustup completions powershell >> ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

    CARGO:

    Rustup can also generate a completion script for `cargo`. The script output
    by `rustup` will source the completion script distributed with your default
    toolchain. Not all shells are currently supported. Here are examples for
    the currently supported shells.

    BASH:

        $ rustup completions bash cargo >> ~/.local/share/bash-completion/completions/cargo

    ZSH:

        $ rustup completions zsh cargo > ~/.zfunc/_cargo";

pub static TOOLCHAIN_ARG_HELP: &str = "Toolchain name, such as 'stable', 'nightly', \
                                       or '1.8.0'. For more information see `rustup \
                                       help toolchain`";

pub static TOPIC_ARG_HELP: &str = "Topic such as 'core', 'fn', 'usize', 'eprintln!', \
                                   'core::arch', 'alloc::format!', 'std::fs', \
                                   'std::fs::read_dir', 'std::io::Bytes', \
                                   'std::iter::Sum', 'std::io::error::Result' etc...";
<commit_msg>Run `cargo fmt` with new beta<commit_after>pub static RUSTUP_HELP: &str = r"DISCUSSION:
    rustup installs The Rust Programming Language from the official
    release channels, enabling you to easily switch between stable,
    beta, and nightly compilers and keep them updated. It makes
    cross-compiling simpler with binary builds of the standard library
    for common platforms.

    If you are new to Rust consider running `rustup doc --book` to
    learn Rust.";

pub static SHOW_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain and the version of `rustc`.

    If the active toolchain has installed support for additional
    compilation targets, then they are listed as well.

    If there are multiple toolchains installed then all installed
    toolchains are listed as well.";

pub static SHOW_ACTIVE_TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain.

    This is useful for figuring out the active tool chain from
    scripts.

    You should use `rustc --print sysroot` to get the sysroot, or
    `rustc --version` to get the toolchain version.";

pub static UPDATE_HELP: &str = r"DISCUSSION:
    With no toolchain specified, the `update` command updates each of
    the installed toolchains from the official release channels, then
    updates rustup itself.

    If given a toolchain argument then `update` updates that
    toolchain, the same as `rustup toolchain install`.";

pub static INSTALL_HELP: &str = r"DISCUSSION:
    Installs a specific rust toolchain.

    The 'install' command is an alias for 'rustup update <toolchain>'.";

pub static DEFAULT_HELP: &str = r"DISCUSSION:
    Sets the default toolchain to the one specified. If the toolchain
    is not already installed then it is installed first.";

pub static TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Many `rustup` commands deal with *toolchains*, a single
    installation of the Rust compiler. `rustup` supports multiple
    types of toolchains. The most basic track the official release
    channels: 'stable', 'beta' and 'nightly'; but `rustup` can also
    install toolchains from the official archives, for alternate host
    platforms, and from local builds.

    Standard release channel toolchain names have the following form:

        <channel>[-<date>][-<host>]

        <channel>       = stable|beta|nightly|<version>
        <date>          = YYYY-MM-DD
        <host>          = <target-triple>

    'channel' is either a named release channel or an explicit version
    number, such as '1.8.0'. Channel names can be optionally appended
    with an archive date, as in 'nightly-2017-05-09', in which case
    the toolchain is downloaded from the archive for that date.

    The host may be specified as a target triple. This is most useful
    for installing a 32-bit compiler on a 64-bit platform, or for
    installing the [MSVC-based toolchain] on Windows. For example:

        $ rustup toolchain install stable-x86_64-pc-windows-msvc

    For convenience, omitted elements of the target triple will be
    inferred, so the above could be written:

        $ rustup toolchain install stable-msvc

    The `rustup default` command may be used to both install and set
    the desired toolchain as default in a single command:

        $ rustup default stable-msvc

    rustup can also manage symlinked local toolchain builds, which are
    often used for developing Rust itself. For more information see
    `rustup toolchain help link`.";

pub static TOOLCHAIN_LINK_HELP: &str = r"DISCUSSION:
    'toolchain' is the custom name to be assigned to the new toolchain.
    Any name is permitted as long as it does not fully match an initial
    substring of a standard release channel. For example, you can use
    the names 'latest' or '2017-04-01' but you cannot use 'stable' or
    'beta-i686' or 'nightly-x86_64-unknown-linux-gnu'.

    'path' specifies the directory where the binaries and libraries for
    the custom toolchain can be found. For example, when used for
    development of Rust itself, toolchains can be linked directly out of
    the build directory. After building, you can test out different
    compiler versions as follows:

        $ rustup toolchain link latest-stage1 build/x86_64-unknown-linux-gnu/stage1
        $ rustup override set latest-stage1

    If you now compile a crate in the current directory, the custom
    toolchain 'latest-stage1' will be used.";

pub static OVERRIDE_HELP: &str = r"DISCUSSION:
    Overrides configure rustup to use a specific toolchain when
    running in a specific directory.

    Directories can be assigned their own Rust toolchain with `rustup
    override`. When a directory has an override then any time `rustc`
    or `cargo` is run inside that directory, or one of its child
    directories, the override toolchain will be invoked.

    To pin to a specific nightly:

        $ rustup override set nightly-2014-12-18

    Or a specific stable release:

        $ rustup override set 1.0.0

    To see the active toolchain use `rustup show`. To remove the
    override and use the default toolchain again, `rustup override
    unset`.";

pub static OVERRIDE_UNSET_HELP: &str = r"DISCUSSION:
    If `--path` argument is present, removes the override toolchain
    for the specified directory. If `--nonexistent` argument is
    present, removes the override toolchain for all nonexistent
    directories. Otherwise, removes the override toolchain for the
    current directory.";

pub static RUN_HELP: &str = r"DISCUSSION:
    Configures an environment to use the given toolchain and then runs
    the specified program. The command may be any program, not just
    rustc or cargo. This can be used for testing arbitrary toolchains
    without setting an override.

    Commands explicitly proxied by `rustup` (such as `rustc` and
    `cargo`) also have a shorthand for this available. The toolchain
    can be set by using `+toolchain` as the first argument. These are
    equivalent:

        $ cargo +nightly build

        $ rustup run nightly cargo build";

pub static DOC_HELP: &str = r"DISCUSSION:
    Opens the documentation for the currently active toolchain with
    the default browser.

    By default, it opens the documentation index. Use the various
    flags to open specific pieces of documentation.";

pub static COMPLETIONS_HELP: &str = r"DISCUSSION:
    Enable tab completion for Bash, Fish, Zsh, or PowerShell
    The script is output on `stdout`, allowing one to re-direct the
    output to the file of their choosing. Where you place the file
    will depend on which shell, and which operating system you are
    using. Your particular configuration may also determine where
    these scripts need to be placed.

    Here are some common set ups for the three supported shells under
    Unix and similar operating systems (such as GNU/Linux).

    BASH:

    Completion files are commonly stored in `/etc/bash_completion.d/` for
    system-wide commands, but can be stored in
    `~/.local/share/bash-completion/completions` for user-specific commands.
    Run the command:

        $ mkdir -p ~/.local/share/bash-completion/completions
        $ rustup completions bash >> ~/.local/share/bash-completion/completions/rustup

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take affect.

    BASH (macOS/Homebrew):

    Homebrew stores bash completion files within the Homebrew directory.
    With the `bash-completion` brew formula installed, run the command:

        $ mkdir -p $(brew --prefix)/etc/bash_completion.d
        $ rustup completions bash > $(brew --prefix)/etc/bash_completion.d/rustup.bash-completion

    FISH:

    Fish completion files are commonly stored in
    `$HOME/.config/fish/completions`. Run the command:

        $ mkdir -p ~/.config/fish/completions
        $ rustup completions fish > ~/.config/fish/completions/rustup.fish

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take affect.

    ZSH:

    ZSH completions are commonly stored in any directory listed in
    your `$fpath` variable. To use these completions, you must either
    add the generated script to one of those directories, or add your
    own to this list.

    Adding a custom directory is often the safest bet if you are
    unsure of which directory to use. First create the directory; for
    this example we'll create a hidden directory inside our `$HOME`
    directory:

        $ mkdir ~/.zfunc

    Then add the following lines to your `.zshrc` just before
    `compinit`:

        fpath+=~/.zfunc

    Now you can install the completions script using the following
    command:

        $ rustup completions zsh > ~/.zfunc/_rustup

    You must then either log out and log back in, or simply run

        $ exec zsh

    for the new completions to take affect.

    CUSTOM LOCATIONS:

    Alternatively, you could save these files to the place of your
    choosing, such as a custom directory inside your $HOME. Doing so
    will require you to add the proper directives, such as `source`ing
    inside your login script. Consult your shells documentation for
    how to add such directives.

    POWERSHELL:

    The powershell completion scripts require PowerShell v5.0+ (which
    comes Windows 10, but can be downloaded separately for windows 7
    or 8.1).

    First, check if a profile has already been set

        PS C:\> Test-Path $profile

    If the above command returns `False` run the following

        PS C:\> New-Item -path $profile -type file -force

    Now open the file provided by `$profile` (if you used the
    `New-Item` command it will be
    `${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`

    Next, we either save the completions file into our profile, or
    into a separate file and source it inside our profile. To save the
    completions into our profile simply use

        PS C:\> rustup completions powershell >> ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

    CARGO:

    Rustup can also generate a completion script for `cargo`. The script output
    by `rustup` will source the completion script distributed with your default
    toolchain. Not all shells are currently supported. Here are examples for
    the currently supported shells.

    BASH:

        $ rustup completions bash cargo >> ~/.local/share/bash-completion/completions/cargo

    ZSH:

        $ rustup completions zsh cargo > ~/.zfunc/_cargo";

pub static TOOLCHAIN_ARG_HELP: &str = "Toolchain name, such as 'stable', 'nightly', \
                                       or '1.8.0'. For more information see `rustup \
                                       help toolchain`";

pub static TOPIC_ARG_HELP: &str = "Topic such as 'core', 'fn', 'usize', 'eprintln!', \
                                   'core::arch', 'alloc::format!', 'std::fs', \
                                   'std::fs::read_dir', 'std::io::Bytes', \
                                   'std::iter::Sum', 'std::io::error::Result' etc...";
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;

extern crate vitral;

use std::rc::Rc;

use glium::{Surface, GlObject};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Texture(GliumTexture);

impl PartialEq<Texture> for Texture {
    fn eq(&self, other: &Texture) -> bool {
        self.0.get_id() == other.0.get_id()
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // compiling shaders and linking them together
    let program = program!(&display,
        150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex;

                out vec4 vColor;
                out vec2 vTexcoord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    vColor = color;
                    vTexcoord = tex;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 vColor;
                in vec2 vTexcoord;
                out vec4 f_color;

                void main() {
                    f_color = vColor * texture(tex, vTexcoord);
                }
            "
        },
    )
                      .unwrap();

    let mut context: Context<Rc<Texture>, Vertex>;
    let builder = vitral::Builder::new();
    context = builder.build(|img| {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(), dim);
        Rc::new(Texture(glium::texture::CompressedSrgbTexture2d::new(&display, raw).unwrap()))
    });

    let font = context.default_font();

    let mut test_input = String::new();

    // the main loop
    loop {
        context.begin_frame();
        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        // drawing a frame

        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: &(*batch.texture).0,
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&display, &batch.vertices).unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(&display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &params).unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                glutin::Event::MouseMoved(x, y) => context.input_mouse_move(x, y),
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => context.input_key_state(vitral::Keycode::Tab, is_down),
                        LShift | RShift => context.input_key_state(vitral::Keycode::Shift, is_down),
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl, is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter, is_down)
                        }
                        Back => context.input_key_state(vitral::Keycode::Backspace, is_down),
                        Delete => context.input_key_state(vitral::Keycode::Del, is_down),
                        Numpad8 | Up => context.input_key_state(vitral::Keycode::Up, is_down),
                        Numpad2 | Down => context.input_key_state(vitral::Keycode::Down, is_down),
                        Numpad4 | Left => context.input_key_state(vitral::Keycode::Left, is_down),
                        Numpad6 | Right => context.input_key_state(vitral::Keycode::Right, is_down),
                        _ => {}
                    }
                }
                _ => (),
            }
        }
    }
}
<commit_msg>Nearest-neighbor sampling in textures<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;

extern crate vitral;

use std::rc::Rc;

use glium::{Surface, GlObject};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Texture(GliumTexture);

impl PartialEq<Texture> for Texture {
    fn eq(&self, other: &Texture) -> bool {
        self.0.get_id() == other.0.get_id()
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // compiling shaders and linking them together
    let program = program!(&display,
        150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex;

                out vec4 vColor;
                out vec2 vTexcoord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    vColor = color;
                    vTexcoord = tex;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 vColor;
                in vec2 vTexcoord;
                out vec4 f_color;

                void main() {
                    f_color = vColor * texture(tex, vTexcoord);
                }
            "
        },
    )
                      .unwrap();

    let mut context: Context<Rc<Texture>, Vertex>;
    let builder = vitral::Builder::new();
    context = builder.build(|img| {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(), dim);
        Rc::new(Texture(glium::texture::CompressedSrgbTexture2d::new(&display, raw).unwrap()))
    });

    let font = context.default_font();

    let mut test_input = String::new();

    // the main loop
    loop {
        context.begin_frame();
        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        // drawing a frame

        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&(*batch.texture).0)
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&display, &batch.vertices).unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(&display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &params).unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                glutin::Event::MouseMoved(x, y) => context.input_mouse_move(x, y),
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => context.input_key_state(vitral::Keycode::Tab, is_down),
                        LShift | RShift => context.input_key_state(vitral::Keycode::Shift, is_down),
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl, is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter, is_down)
                        }
                        Back => context.input_key_state(vitral::Keycode::Backspace, is_down),
                        Delete => context.input_key_state(vitral::Keycode::Del, is_down),
                        Numpad8 | Up => context.input_key_state(vitral::Keycode::Up, is_down),
                        Numpad2 | Down => context.input_key_state(vitral::Keycode::Down, is_down),
                        Numpad4 | Left => context.input_key_state(vitral::Keycode::Left, is_down),
                        Numpad6 | Right => context.input_key_state(vitral::Keycode::Right, is_down),
                        _ => {}
                    }
                }
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate hyper;
extern crate env_logger;
extern crate num_cpus;

use std::io::Write;

use hyper::{Decoder, Encoder, Next};
use hyper::net::{HttpStream, HttpListener};
use hyper::server::{Server, Handler, Request, Response};

static PHRASE: &'static [u8] = b"Hello World!";

struct Hello;

impl Handler<HttpStream> for Hello {
    fn on_request(&mut self, _: Request) -> Next {
        Next::write()
    }
    fn on_request_readable(&mut self, _: &mut Decoder<HttpStream>) -> Next {
        Next::write()
    }
    fn on_response(&mut self, response: &mut Response) -> Next {
        use hyper::header::ContentLength;
        response.headers_mut().set(ContentLength(PHRASE.len() as u64));
        Next::write()
    }
    fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
        let n = encoder.write(PHRASE).unwrap();
        debug_assert_eq!(n, PHRASE.len());
        Next::end()
    }
}

fn main() {
    env_logger::init().unwrap();

    let listener = HttpListener::bind(&"127.0.0.1:3000".parse().unwrap()).unwrap();
    let mut handles = Vec::new();

    for _ in 0..num_cpus::get() {
        let listener = listener.try_clone().unwrap();
        handles.push(::std::thread::spawn(move || {
            Server::new(listener)
                .handle(|_| Hello).unwrap()
        }));
    }
    println!("Listening on http://127.0.0.1:3000");

    for handle in handles {
        handle.join().unwrap();
    }
}
<commit_msg>fix(examples): hello example fix for multithread (#808)<commit_after>#![deny(warnings)]
extern crate hyper;
extern crate env_logger;
extern crate num_cpus;

use std::io::Write;

use hyper::{Decoder, Encoder, Next};
use hyper::net::{HttpStream, HttpListener};
use hyper::server::{Server, Handler, Request, Response};

static PHRASE: &'static [u8] = b"Hello World!";

struct Hello;

impl Handler<HttpStream> for Hello {
    fn on_request(&mut self, _: Request) -> Next {
        Next::write()
    }
    fn on_request_readable(&mut self, _: &mut Decoder<HttpStream>) -> Next {
        Next::write()
    }
    fn on_response(&mut self, response: &mut Response) -> Next {
        use hyper::header::ContentLength;
        response.headers_mut().set(ContentLength(PHRASE.len() as u64));
        Next::write()
    }
    fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
        let n = encoder.write(PHRASE).unwrap();
        debug_assert_eq!(n, PHRASE.len());
        Next::end()
    }
}

fn main() {
    env_logger::init().unwrap();

    let listener = HttpListener::bind(&"127.0.0.1:3000".parse().unwrap()).unwrap();
    let mut handles = Vec::new();

    for _ in 0..num_cpus::get() {
        let listener = listener.try_clone().unwrap();
        handles.push(::std::thread::spawn(move || {
            Server::new(listener)
                .handle(|_| Hello).unwrap();
        }));
    }
    println!("Listening on http://127.0.0.1:3000");

    for handle in handles {
        handle.join().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate crc;

use std::io;
use std::io::{BufWriter, ErrorKind, Write, Seek, SeekFrom, Result, Error};
use self::byteorder::{ByteOrder, WriteBytesExt, LittleEndian};
use self::crc::{crc32, Hasher32};

use definitions::*;

// We limit how far copy back-references can go, the same as the C++ code.
const MAX_OFFSET: usize = 1 << 15;

// The Max Encoded Length of the Max Chunk of 65536 bytes
const MAX_BUFFER_SIZE: usize = 76_490;

pub struct Compressor<W: Write> {
    inner: BufWriter<W>,
    pos: u64,
    buf_body: [u8; MAX_BUFFER_SIZE],
    buf_header: [u8; (CHECK_SUM_SIZE + CHUNK_HEADER_SIZE) as usize],
    wrote_header: bool,
}

impl <W: Write> Compressor<W> {

    pub fn new(inner: W) -> Compressor<W> {
        Compressor {
            inner: BufWriter::new(inner),
            pos: 0,
            buf_body: [0; MAX_BUFFER_SIZE],
            buf_header: [0; (CHECK_SUM_SIZE + CHUNK_HEADER_SIZE) as usize],
            wrote_header: false,
        }
    }
}

impl <W: Write> Write for Compressor<W> {
    // Implement Write
    // Source Buffer -> Destination (Inner) Buffer
    fn write(&mut self, src: &[u8]) -> Result<usize> {

        let mut written: usize = 0;

        if !self.wrote_header {
            // Write Stream Literal
            try!(self.inner.write(&MAGIC_CHUNK));
            self.wrote_header = true;
        }

        // Split source into chunks of 65536 bytes each.
        for src_chunk in src.chunks(MAX_UNCOMPRESSED_CHUNK_LEN as usize) {

            // TODO
            // Handle Written Slice Length (Ignore Previous Garbage)
            let chunk_body: &[u8];
            let chunk_type: u8;

            // Create Checksum
            let checksum: u32 = crc32::checksum_ieee(src_chunk);

            // Compress the buffer, discarding the result if the improvement
            // isn't at least 12.5%.
            let n = try!(compress(&mut self.buf_body, src_chunk));
            if n >= src_chunk.len() * (7 / 8) {
                chunk_type = CHUNK_TYPE_UNCOMPRESSED_DATA;
                chunk_body = src_chunk;
            } else {
                chunk_type = CHUNK_TYPE_COMPRESSED_DATA;
                chunk_body = self.buf_body.split_at(n).0;
            }

            let chunk_len = chunk_body.len() + 4;

            // Write Chunk Type
            self.buf_header[0] = chunk_type;
            // Write Chunk Length
            self.buf_header[1] = (chunk_len >> 0) as u8;
            self.buf_header[2] = (chunk_len >> 8) as u8;
            self.buf_header[3] = (chunk_len >> 16) as u8;
            // Write Chunk Checksum
            self.buf_header[4] = (checksum >> 0) as u8;
            self.buf_header[5] = (checksum >> 8) as u8;
            self.buf_header[6] = (checksum >> 16) as u8;
            self.buf_header[7] = (checksum >> 24) as u8;

            // Write Chunk Header and Handle Error
            try!(self.inner.write_all(&self.buf_header));
            // Write Chunk Body and Handle Error
            try!(self.inner.write_all(chunk_body));

            // If all goes well, count written length as uncompressed length
            written += src_chunk.len();
        }

        Ok(written)
    }

    // Flushes Inner buffer and resets Compressor
    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

// If Compressor is Given a Cursor or Seekable Writer
// This Gives the BufWriter the seek method
impl <W: Write + Seek> Seek for Compressor<W> {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.inner.seek(pos).and_then(|res: u64| {
            self.pos = res;
            Ok(res)
        })
    }
}

// Compress writes the encoded form of src into dst and return the length
// written.
// Returns an error if dst was not large enough to hold the entire encoded
// block.

// (Future) Include a Legacy Compress??
pub fn compress(dst: &mut [u8], src: &[u8]) -> io::Result<usize> {
    if dst.len() < max_compressed_len(src.len()) {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: destination buffer is too short"));
    }

    // Start Block with varint-encoded length of decompressed bytes
    LittleEndian::write_u64(dst, src.len() as u64);

    let mut d: usize = 4;

    // Return early if src is short
    if src.len() <= 4 {
        if src.len() != 0 {
            // TODO Handle Error
            d += emit_literal(dst.split_at_mut(d).1, src).unwrap();
        }
        return Ok(d);
    }

    // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
    const MAX_TABLE_SIZE: usize = 1 << 14;
    let mut shift: u32 = 24;
    let mut table_size: usize = 1 << 8;

    while table_size < MAX_TABLE_SIZE && table_size < src.len() {
        shift -= 1;
        table_size *= 2;
    }

    // Create table
    let mut table: Vec<i32> = vec![0; MAX_TABLE_SIZE];

    // Iterate over the source bytes
    let mut s: usize = 0;
    let mut t: i32;
    let mut lit: usize = 0;

    // (Future) Iterate in chunks of 4?
    while s + 3 < src.len() {

        // Grab 4 bytes
        let b: (u8, u8, u8, u8) = (src[s], src[s + 1], src[s + 2], src[s + 3]);

        // Create u32 for Hashing
        let h: u32 = (b.0 as u32) | ((b.1 as u32) << 8) | ((b.2 as u32) << 16) | ((b.3 as u32) << 24);

        // Update the hash table
        let ref mut p: i32 = table[(h.wrapping_mul(0x1e35a7bd) >> shift) as usize];

        // We need to to store values in [-1, inf) in table. To save
        // some initialization time, (re)use the table's zero value
        // and shift the values against this zero: add 1 on writes,
        // subtract 1 on reads.

        // If Hash Exists t = 0; if not t = -1;
        t = *p - 1;

        // Set Position of new Hash -> i32
        *p = (s + 1) as i32;

        // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal
        // byte.
        if t < 0 ||
            s.wrapping_sub(t as usize) >= MAX_OFFSET ||
            b.0 != src[t as usize] ||
            b.1 != src[(t + 1) as usize] ||
            b.2 != src[(t + 2) as usize] ||
            b.3 != src[(t + 3) as usize] {
            s += 1;
            continue;
        }

        // Otherwise, we have a match. First, emit any pending literal bytes.
        // Panics on d > dst.len();
        if lit != s {

            d += try!(emit_literal(dst.split_at_mut(d).1,

                // Handle Split_at mid < src check
                {
                    let _lit = src.split_at(lit).1;
                    if _lit.len() > s {
                        _lit.split_at(s).0
                    } else {
                        _lit
                    }
                }));
        }

        // Extend the match to be as long as possible
        let s0 = s;
        s += 4;
        t += 4;
        while s < src.len() && src[s] == src[t as usize] {
            s += 1;
            t += 1;
        }

        // Emit the copied bytes.
        d += emit_copy(dst.split_at_mut(d).1, s.wrapping_sub(t as usize), s - s0);
        lit = s;
    }

    // Emit any final pending literal bytes and return.
    if lit != src.len() {
        d += emit_literal(dst.split_at_mut(d).1, src.split_at(lit).1).unwrap();
    }

    Ok(d)
}

// emitLiteral writes a literal chunk and returns the number of bytes written.
fn emit_literal(dst: &mut [u8], lit: &[u8]) -> io::Result<usize> {

    let i: usize;
    let n: u64 = (lit.len() - 1) as u64;

    if n < 60 {
        dst[0] = (n as u8) << 2 | TAG_LITERAL;
        i = 1;
    } else if n < 1 << 8 {
        dst[0] = 60 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        i = 2;
    } else if n < 1 << 16 {
        dst[0] = 61 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        dst[2] = (n >> 8) as u8;
        i = 3;
    } else if n < 1 << 24 {
        dst[0] = 62 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        dst[2] = (n >> 8) as u8;
        dst[3] = (n >> 16) as u8;
        i = 4;
    } else if n < 1 << 32 {
        dst[0] = 63 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        dst[2] = (n >> 8) as u8;
        dst[3] = (n >> 16) as u8;
        dst[4] = (n >> 24) as u8;
        i = 5;
    } else {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: source buffer is too long"));
    }

    let mut s = 0;
    for (d, l) in dst.split_at_mut(i).1.iter_mut().zip(lit.iter()) {
        *d = *l;
        s += 1;
    }

    if s == lit.len() {
        Ok(i + lit.len())
    } else {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: destination buffer is too short"));
    }
}

// emitCopy writes a copy chunk and returns the number of bytes written.
fn emit_copy(dst: &mut [u8], offset: usize, mut length: usize) -> usize {

    let mut i: usize = 0;

    while length > 0 {
        // TODO: Handle Overflow
        let mut x = length - 4;
        if 0 <= x && x < 1 << 3 && offset < 1 << 11 {
            dst[i] = ((offset >> 8) as u8) & 0x07 << 5 | (x as u8) << 2 | TAG_COPY_1;
            dst[i + 1] = offset as u8;
            i += 2;
            break;
        }
        x = length;
        if x > 1 << 6 {
            x = 1 << 6;
        }
        dst[i] = ((x as u8) - 1) << 2 | TAG_COPY_2;
        dst[i + 1] = offset as u8;
        dst[i + 2] = (offset >> 8) as u8;
        i += 3;
        length -= x;
    }
    // (Future) Return a `Result<usize>` Instead??
    i
}

// max_compressed_len returns the maximum length of a snappy block, given its
// uncompressed length.
pub fn max_compressed_len(src_len: usize) -> usize {
    32 + src_len + src_len / 6
}
<commit_msg>Fix Compressor Bug on Slice Split<commit_after>extern crate byteorder;
extern crate crc;

use std::io;
use std::io::{BufWriter, ErrorKind, Write, Seek, SeekFrom, Result, Error};
use self::byteorder::{ByteOrder, WriteBytesExt, LittleEndian};
use self::crc::{crc32, Hasher32};

use definitions::*;

// We limit how far copy back-references can go, the same as the C++ code.
const MAX_OFFSET: usize = 1 << 15;

// The Max Encoded Length of the Max Chunk of 65536 bytes
const MAX_BUFFER_SIZE: usize = 76_490;

pub struct Compressor<W: Write> {
    inner: BufWriter<W>,
    pos: u64,
    buf_body: [u8; MAX_BUFFER_SIZE],
    buf_header: [u8; (CHECK_SUM_SIZE + CHUNK_HEADER_SIZE) as usize],
    wrote_header: bool,
}

impl <W: Write> Compressor<W> {

    pub fn new(inner: W) -> Compressor<W> {
        Compressor {
            inner: BufWriter::new(inner),
            pos: 0,
            buf_body: [0; MAX_BUFFER_SIZE],
            buf_header: [0; (CHECK_SUM_SIZE + CHUNK_HEADER_SIZE) as usize],
            wrote_header: false,
        }
    }
}

impl <W: Write> Write for Compressor<W> {
    // Implement Write
    // Source Buffer -> Destination (Inner) Buffer
    fn write(&mut self, src: &[u8]) -> Result<usize> {

        let mut written: usize = 0;

        if !self.wrote_header {
            // Write Stream Literal
            try!(self.inner.write(&MAGIC_CHUNK));
            self.wrote_header = true;
        }

        // Split source into chunks of 65536 bytes each.
        for src_chunk in src.chunks(MAX_UNCOMPRESSED_CHUNK_LEN as usize) {

            // TODO
            // Handle Written Slice Length (Ignore Previous Garbage)
            let chunk_body: &[u8];
            let chunk_type: u8;

            // Create Checksum
            let checksum: u32 = crc32::checksum_ieee(src_chunk);

            // Compress the buffer, discarding the result if the improvement
            // isn't at least 12.5%.
            let n = try!(compress(&mut self.buf_body, src_chunk));
            if n >= src_chunk.len() * (7 / 8) {
                chunk_type = CHUNK_TYPE_UNCOMPRESSED_DATA;
                chunk_body = src_chunk;
            } else {
                chunk_type = CHUNK_TYPE_COMPRESSED_DATA;
                chunk_body = self.buf_body.split_at(n).0;
            }

            let chunk_len = chunk_body.len() + 4;

            // Write Chunk Type
            self.buf_header[0] = chunk_type;
            // Write Chunk Length
            self.buf_header[1] = (chunk_len >> 0) as u8;
            self.buf_header[2] = (chunk_len >> 8) as u8;
            self.buf_header[3] = (chunk_len >> 16) as u8;
            // Write Chunk Checksum
            self.buf_header[4] = (checksum >> 0) as u8;
            self.buf_header[5] = (checksum >> 8) as u8;
            self.buf_header[6] = (checksum >> 16) as u8;
            self.buf_header[7] = (checksum >> 24) as u8;

            // Write Chunk Header and Handle Error
            try!(self.inner.write_all(&self.buf_header));
            // Write Chunk Body and Handle Error
            try!(self.inner.write_all(chunk_body));

            // If all goes well, count written length as uncompressed length
            written += src_chunk.len();
        }

        Ok(written)
    }

    // Flushes Inner buffer and resets Compressor
    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

// If Compressor is Given a Cursor or Seekable Writer
// This Gives the BufWriter the seek method
impl <W: Write + Seek> Seek for Compressor<W> {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.inner.seek(pos).and_then(|res: u64| {
            self.pos = res;
            Ok(res)
        })
    }
}

// Compress writes the encoded form of src into dst and return the length
// written.
// Returns an error if dst was not large enough to hold the entire encoded
// block.

// (Future) Include a Legacy Compress??
pub fn compress(dst: &mut [u8], src: &[u8]) -> io::Result<usize> {

    if dst.len() < max_compressed_len(src.len()) {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: destination buffer is too short"));
    }

    // Start Block with varint-encoded length of decompressed bytes
    LittleEndian::write_u64(dst, src.len() as u64);

    let mut d: usize = 4;

    // Return early if src is short
    if src.len() <= 4 {
        if src.len() != 0 {
            // TODO Handle Error
            d += emit_literal(dst.split_at_mut(d).1, src).unwrap();
        }
        return Ok(d);
    }

    // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
    const MAX_TABLE_SIZE: usize = 1 << 14;
    let mut shift: u32 = 24;
    let mut table_size: usize = 1 << 8;

    while table_size < MAX_TABLE_SIZE && table_size < src.len() {
        shift -= 1;
        table_size *= 2;
    }

    // Create table
    let mut table: Vec<i32> = vec![0; MAX_TABLE_SIZE];

    // Iterate over the source bytes
    let mut s: usize = 0;
    let mut t: i32;
    let mut lit: usize = 0;

    // (Future) Iterate in chunks of 4?
    while s + 3 < src.len() {

        // Grab 4 bytes
        let b: (u8, u8, u8, u8) = (src[s], src[s + 1], src[s + 2], src[s + 3]);

        // Create u32 for Hashing
        let h: u32 = (b.0 as u32) | ((b.1 as u32) << 8) | ((b.2 as u32) << 16) | ((b.3 as u32) << 24);

        // Update the hash table
        let ref mut p: i32 = table[(h.wrapping_mul(0x1e35a7bd) >> shift) as usize];

        // We need to to store values in [-1, inf) in table. To save
        // some initialization time, (re)use the table's zero value
        // and shift the values against this zero: add 1 on writes,
        // subtract 1 on reads.

        // If Hash Exists t = 0; if not t = -1;
        t = *p - 1;

        // Set Position of new Hash -> i32
        *p = (s + 1) as i32;

        // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal
        // byte.
        if t < 0 ||
            s.wrapping_sub(t as usize) >= MAX_OFFSET ||
            b.0 != src[t as usize] ||
            b.1 != src[(t + 1) as usize] ||
            b.2 != src[(t + 2) as usize] ||
            b.3 != src[(t + 3) as usize] {
            s += 1;
            continue;
        }

        // Otherwise, we have a match. First, emit any pending literal bytes.
        // Panics on d > dst.len();

        if lit != s {
            d += try!(emit_literal(dst.split_at_mut(d).1,

                // Handle Split_at mid < src check
                {
                    if src.len() > s {
                        src.split_at(s).0.split_at(lit).1
                    } else {
                        src.split_at(lit).1
                    }
                }));
        }

        // Extend the match to be as long as possible
        let s0 = s;
        s += 4;
        t += 4;
        while s < src.len() && src[s] == src[t as usize] {
            s += 1;
            t += 1;
        }

        // Emit the copied bytes.
        d += emit_copy(dst.split_at_mut(d).1, s.wrapping_sub(t as usize), s - s0);
        lit = s;
    }

    // Emit any final pending literal bytes and return.
    if lit != src.len() {
        d += emit_literal(dst.split_at_mut(d).1, src.split_at(lit).1).unwrap();
    }

    Ok(d)
}

// emitLiteral writes a literal chunk and returns the number of bytes written.
fn emit_literal(dst: &mut [u8], lit: &[u8]) -> io::Result<usize> {

    let i: usize;
    let n: u64 = (lit.len() - 1) as u64;

    if n < 60 {
        dst[0] = (n as u8) << 2 | TAG_LITERAL;
        i = 1;
    } else if n < 1 << 8 {
        dst[0] = 60 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        i = 2;
    } else if n < 1 << 16 {
        dst[0] = 61 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        dst[2] = (n >> 8) as u8;
        i = 3;
    } else if n < 1 << 24 {
        dst[0] = 62 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        dst[2] = (n >> 8) as u8;
        dst[3] = (n >> 16) as u8;
        i = 4;
    } else if n < 1 << 32 {
        dst[0] = 63 << 2 | TAG_LITERAL;
        dst[1] = n as u8;
        dst[2] = (n >> 8) as u8;
        dst[3] = (n >> 16) as u8;
        dst[4] = (n >> 24) as u8;
        i = 5;
    } else {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: source buffer is too long"));
    }

    let mut s = 0;
    for (d, l) in dst.split_at_mut(i).1.iter_mut().zip(lit.iter()) {
        *d = *l;
        s += 1;
    }

    if s == lit.len() {
        Ok(i + lit.len())
    } else {
        return Err(Error::new(ErrorKind::InvalidInput, "snappy: destination buffer is too short"));
    }
}

// emitCopy writes a copy chunk and returns the number of bytes written.
fn emit_copy(dst: &mut [u8], offset: usize, mut length: usize) -> usize {

    let mut i: usize = 0;

    while length > 0 {
        // TODO: Handle Overflow
        let mut x = length - 4;
        if 0 <= x && x < 1 << 3 && offset < 1 << 11 {
            dst[i] = ((offset >> 8) as u8) & 0x07 << 5 | (x as u8) << 2 | TAG_COPY_1;
            dst[i + 1] = offset as u8;
            i += 2;
            break;
        }
        x = length;
        if x > 1 << 6 {
            x = 1 << 6;
        }
        dst[i] = ((x as u8) - 1) << 2 | TAG_COPY_2;
        dst[i + 1] = offset as u8;
        dst[i + 2] = (offset >> 8) as u8;
        i += 3;
        length -= x;
    }
    // (Future) Return a `Result<usize>` Instead??
    i
}

// max_compressed_len returns the maximum length of a snappy block, given its
// uncompressed length.
pub fn max_compressed_len(src_len: usize) -> usize {
    32 + src_len + src_len / 6
}
<|endoftext|>