<commit_before>use std::mem;
use std::num::Int;

/// constant-time compare function.
/// `a` and `b` may be SECRET, but the length is known.
/// precondition: `a.len() == b.len()`
pub fn crypto_compare(a: &[u8], b: &[u8]) -> bool {
    debug_assert_eq!(a.len(), b.len());

    let mut diff = 0u8;
    for i in (0..a.len()) {
        diff |= a[i] ^ b[i];
    }
    diff = diff | (diff >> 4);
    diff = diff | (diff >> 2);
    diff = diff | (diff >> 1);
    diff = diff & 1;
    return diff == 0;
}

pub fn u64_be_array(x: u64) -> [u8; 8] {
    unsafe { mem::transmute(x.to_be()) }
}

pub fn u64_le_array(x: u64) -> [u8; 8] {
    unsafe { mem::transmute(x.to_le()) }
}
<commit_msg>util: Add ReadExt and WriteExt traits<commit_after>use std::mem;
use std::num::Int;
use std::io::{self, Read, Write};

/// constant-time compare function.
/// `a` and `b` may be SECRET, but the length is known.
/// precondition: `a.len() == b.len()`
pub fn crypto_compare(a: &[u8], b: &[u8]) -> bool {
    debug_assert_eq!(a.len(), b.len());

    let mut diff = 0u8;
    for i in (0..a.len()) {
        diff |= a[i] ^ b[i];
    }
    diff = diff | (diff >> 4);
    diff = diff | (diff >> 2);
    diff = diff | (diff >> 1);
    diff = diff & 1;
    return diff == 0;
}

pub fn u64_be_array(x: u64) -> [u8; 8] {
    unsafe { mem::transmute(x.to_be()) }
}

pub fn u64_le_array(x: u64) -> [u8; 8] {
    unsafe { mem::transmute(x.to_le()) }
}

// native endians.
macro_rules! read_write_prim {
    ($read_name:ident, $write_name:ident, $t:ty, $len:expr) => (
        #[inline(always)]
        fn $read_name<R: ?Sized + ReadExt>(mut reader: &mut R) -> io::Result<$t> {
            let mut buf = [0u8; $len];
            try!(reader.fill_exact(&mut buf));
            let value: $t = unsafe { mem::transmute(buf) };
            Ok(value)
        }
        #[inline(always)]
        fn $write_name<R: ?Sized + Write>(mut writer: &mut R, value: $t) -> io::Result<()> {
            let buf: [u8; $len] = unsafe { mem::transmute(value) };
            try!(writer.write_all(&buf));
            Ok(())
        }
    )
}

read_write_prim!(read_u8, write_u8, u8, 1);
read_write_prim!(read_u16, write_u16, u16, 2);
read_write_prim!(read_u32, write_u32, u32, 4);
read_write_prim!(read_u64, write_u64, u64, 8);

pub trait ReadExt: Read {
    /// Fill buf completely or return `Err`.
    /// NOTE: the default implementation returns `Err(io::ErrorKind::Other)` if EOF is found.
    /// this may be not desired if the source is non-blocking.
    #[inline(always)]
    fn fill_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        let len = buf.len();
        let mut pos = 0;
        while pos < len {
            let num_bytes = try!(self.read(&mut buf[pos..]));
            if num_bytes == 0 {
                return Err(io::Error::new(io::ErrorKind::Other, "EOF during `fill_exact`", None));
            }
            pos += num_bytes;
        }
        Ok(())
    }

    #[inline(always)]
    fn read_exact(&mut self, len: usize) -> io::Result<Vec<u8>> {
        // FIXME this can be more efficient using unsafe methods
        let mut vec = vec![0u8; len];
        try!(self.fill_exact(&mut vec));
        Ok(vec)
    }

    #[inline(always)]
    fn read_u8(&mut self) -> io::Result<u8> {
        read_u8(self)
    }
    #[inline(always)]
    fn read_be_u16(&mut self) -> io::Result<u16> {
        let value: u16 = try!(read_u16(self));
        Ok(value.to_be())
    }
    #[inline(always)]
    fn read_le_u16(&mut self) -> io::Result<u16> {
        let value: u16 = try!(read_u16(self));
        Ok(value.to_le())
    }
    #[inline(always)]
    fn read_be_u32(&mut self) -> io::Result<u32> {
        let value: u32 = try!(read_u32(self));
        Ok(value.to_be())
    }
    #[inline(always)]
    fn read_le_u32(&mut self) -> io::Result<u32> {
        let value: u32 = try!(read_u32(self));
        Ok(value.to_le())
    }
    #[inline(always)]
    fn read_be_u64(&mut self) -> io::Result<u64> {
        let value: u64 = try!(read_u64(self));
        Ok(value.to_be())
    }
    #[inline(always)]
    fn read_le_u64(&mut self) -> io::Result<u64> {
        let value: u64 = try!(read_u64(self));
        Ok(value.to_le())
    }
}

impl<R: Read> ReadExt for R {}

pub trait WriteExt: Write {
    #[inline(always)]
    fn write_u8(&mut self, value: u8) -> io::Result<()> {
        write_u8(self, value)
    }

    #[inline(always)]
    fn write_be_u16(&mut self, value: u16) -> io::Result<()> {
        write_u16(self, value.to_be())
    }
    #[inline(always)]
    fn write_le_u16(&mut self, value: u16) -> io::Result<()> {
        write_u16(self, value.to_le())
    }

    #[inline(always)]
    fn write_be_u32(&mut self, value: u32) -> io::Result<()> {
        write_u32(self, value.to_be())
    }
    #[inline(always)]
    fn write_le_u32(&mut self, value: u32) -> io::Result<()> {
        write_u32(self, value.to_le())
    }

    #[inline(always)]
    fn write_be_u64(&mut self, value: u64) -> io::Result<()> {
        write_u64(self, value.to_be())
    }
    #[inline(always)]
    fn write_le_u64(&mut self, value: u64) -> io::Result<()> {
        write_u64(self, value.to_le())
    }
}

impl<W: Write> WriteExt for W {}
<|endoftext|>


<commit_before>use crate::header::HeaderMap;

// xor-shift
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn fast_random() -> u64 {
    use std::cell::Cell;
    use std::collections::hash_map::RandomState;
    use std::hash::{BuildHasher, Hasher};
    use std::num::Wrapping;

    thread_local! {
        static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
    }

    fn seed() -> u64 {
        let seed = RandomState::new();

        let mut out = 0;
        let mut cnt = 0;
        while out == 0 {
            cnt += 1;
            let mut hasher = seed.build_hasher();
            hasher.write_usize(cnt);
            out = hasher.finish();
        }
        out
    }

    RNG.with(|rng| {
        let mut n = rng.get();
        debug_assert_ne!(n.0, 0);
        n ^= n >> 12;
        n ^= n << 25;
        n ^= n >> 27;
        rng.set(n);
        n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
    })
}

pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
    // IntoIter of HeaderMap yields (Option<HeaderName>, HeaderValue).
    // The first time a name is yielded, it will be Some(name), and if
    // there are more values with the same name, the next yield will be
    // None.
    //
    // TODO: a complex exercise would be to optimize this to only
    // require 1 hash/lookup of the key, but doing something fancy
    // with header::Entry...

    let mut prev_name = None;
    for (key, value) in src {
        match key {
            Some(key) => {
                dst.insert(key.clone(), value);
                prev_name = Some(key);
            }
            None => match prev_name {
                Some(ref key) => {
                    dst.append(key.clone(), value);
                }
                None => unreachable!("HeaderMap::into_iter yielded None first"),
            },
        }
    }
}
<commit_msg>Optimize `replace_headers` to avoid copies of keys<commit_after>use crate::header::{Entry, HeaderMap, OccupiedEntry};

// xor-shift
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn fast_random() -> u64 {
    use std::cell::Cell;
    use std::collections::hash_map::RandomState;
    use std::hash::{BuildHasher, Hasher};
    use std::num::Wrapping;

    thread_local! {
        static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
    }

    fn seed() -> u64 {
        let seed = RandomState::new();

        let mut out = 0;
        let mut cnt = 0;
        while out == 0 {
            cnt += 1;
            let mut hasher = seed.build_hasher();
            hasher.write_usize(cnt);
            out = hasher.finish();
        }
        out
    }

    RNG.with(|rng| {
        let mut n = rng.get();
        debug_assert_ne!(n.0, 0);
        n ^= n >> 12;
        n ^= n << 25;
        n ^= n >> 27;
        rng.set(n);
        n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
    })
}

pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
    // IntoIter of HeaderMap yields (Option<HeaderName>, HeaderValue).
    // The first time a name is yielded, it will be Some(name), and if
    // there are more values with the same name, the next yield will be
    // None.

    let mut prev_entry: Option<OccupiedEntry<_>> = None;
    for (key, value) in src {
        match key {
            Some(key) => match dst.entry(key) {
                Entry::Occupied(mut e) => {
                    e.insert(value);
                    prev_entry = Some(e);
                }
                Entry::Vacant(e) => {
                    let e = e.insert_entry(value);
                    prev_entry = Some(e);
                }
            },
            None => match prev_entry {
                Some(ref mut entry) => {
                    entry.append(value);
                }
                None => unreachable!("HeaderMap::into_iter yielded None first"),
            },
        }
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;

use std::io::ErrorKind;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        append("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l git2:static");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            append("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            append("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn append(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let val = env::join_paths(env::split_paths(&prefix)
                                  .chain(Some(val).into_iter())).unwrap();
    env::set_var(var, &val);
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<commit_msg>Replace old static link flag syntax in build.rs<commit_after>extern crate pkg_config;

use std::io::ErrorKind;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        append("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l static=git2");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            append("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            append("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn append(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let val = env::join_paths(env::split_paths(&prefix)
                                  .chain(Some(val).into_iter())).unwrap();
    env::set_var(var, &val);
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![feature(old_orphan_check)]

extern crate "rustc-serialize" as rustc_serialize;

extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

docopt!(Args derive Show, "
Usage: rustc [options] [--cfg SPEC... -L PATH...] INPUT
       rustc (--help | --version)

Options:
    -h, --help         Show this message.
    --version          Show the version of rustc.
    --cfg SPEC         Configure the compilation environment.
    -L PATH            Add a directory to the library search path.
    --emit TYPE        Configure the output that rustc will produce.
                       Valid values: asm, ir, bc, obj, link.
    --opt-level LEVEL  Optimize with possible levels 0-3.
", flag_opt_level: Option<OptLevel>, flag_emit: Option<Emit>);

#[derive(RustcDecodable, Show)]
enum Emit { Asm, Ir, Bc, Obj, Link }

#[derive(Show)]
enum OptLevel { Zero, One, Two, Three }

impl<E, D> rustc_serialize::Decodable<D, E> for OptLevel
        where D: rustc_serialize::Decoder<E> {
    fn decode(d: &mut D) -> Result<OptLevel, E> {
        Ok(match try!(d.read_uint()) {
            0 => OptLevel::Zero, 1 => OptLevel::One,
            2 => OptLevel::Two, 3 => OptLevel::Three,
            n => {
                let err = format!("Could not decode '{}' as opt-level.", n);
                return Err(d.error(err.as_slice()));
            }
        })
    }
}

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    println!("{}", args);
}
<commit_msg>[docopt_macros] Update to rustc 0.13.0-nightly (c7dd3c4d6 2015-01-05 23:51:00 +0000)<commit_after>#![feature(phase)]

extern crate "rustc-serialize" as rustc_serialize;

extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

docopt!(Args derive Show, "
Usage: rustc [options] [--cfg SPEC... -L PATH...] INPUT
       rustc (--help | --version)

Options:
    -h, --help         Show this message.
    --version          Show the version of rustc.
    --cfg SPEC         Configure the compilation environment.
    -L PATH            Add a directory to the library search path.
    --emit TYPE        Configure the output that rustc will produce.
                       Valid values: asm, ir, bc, obj, link.
    --opt-level LEVEL  Optimize with possible levels 0-3.
", flag_opt_level: Option<OptLevel>, flag_emit: Option<Emit>);

#[derive(RustcDecodable, Show)]
enum Emit { Asm, Ir, Bc, Obj, Link }

#[derive(Show)]
enum OptLevel { Zero, One, Two, Three }

impl rustc_serialize::Decodable for OptLevel {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<OptLevel, D::Error> {
        Ok(match try!(d.read_uint()) {
            0 => OptLevel::Zero, 1 => OptLevel::One,
            2 => OptLevel::Two, 3 => OptLevel::Three,
            n => {
                let err = format!("Could not decode '{}' as opt-level.", n);
                return Err(d.error(err.as_slice()));
            }
        })
    }
}

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    println!("{}", args);
}
<|endoftext|>


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

use std::collections::HashMap;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

use futures::{Async, Future, Poll};
use grpc_sys::{self, GrpcCallStatus, GrpcServer};

use RpcContext;
use async::{CallTag, CqFuture};
use call::{Method, MethodType};
use call::server::*;
use channel::ChannelArgs;
use cq::CompletionQueue;
use env::Environment;
use error::{Error, Result};

const DEFAULT_REQUEST_SLOTS_PER_CQ: usize = 1024;

pub type CallBack = Box<Fn(RpcContext, &[u8])>;

/// Handler is an rpc call holder.
pub struct Handler {
    method_type: MethodType,
    cb: CallBack,
}

impl Handler {
    pub fn new(method_type: MethodType, cb: CallBack) -> Handler {
        Handler {
            method_type: method_type,
            cb: cb,
        }
    }

    pub fn cb(&self) -> &CallBack {
        &self.cb
    }

    pub fn method_type(&self) -> MethodType {
        self.method_type
    }
}

#[cfg(feature = "secure")]
mod imp {
    use grpc_sys::{self, GrpcServer};

    use credentials::ServerCredentials;

    pub struct Binder {
        pub host: String,
        pub port: u16,
        cred: Option<ServerCredentials>,
    }

    impl Binder {
        pub fn new(host: String, port: u16) -> Binder {
            let cred = None;
            Binder { host, port, cred }
        }

        pub fn with_cred(host: String, port: u16, cred: ServerCredentials) -> Binder {
            let cred = Some(cred);
            Binder { host, port, cred }
        }

        pub unsafe fn bind(&mut self, server: *mut GrpcServer) -> u16 {
            let addr = format!("{}:{}\0", self.host, self.port);
            let port = match self.cred.take() {
                None => grpc_sys::grpc_server_add_insecure_http2_port(server, addr.as_ptr() as _),
                Some(mut cert) => grpc_sys::grpc_server_add_secure_http2_port(server, addr.as_ptr() as _, cert.as_mut_ptr())
            };
            port as u16
        }
    }
}

#[cfg(not(feature = "secure"))]
mod imp {
    use grpc_sys::{self, GrpcServer};

    pub struct Binder {
        pub host: String,
        pub port: u16,
    }

    impl Binder {
        pub fn new(host: String, port: u16) -> Binder {
            Binder { host, port }
        }

        pub unsafe fn bind(&self, server: *mut GrpcServer) -> u16 {
            let addr = format!("{}:{}\0", self.host, self.port);
            grpc_sys::grpc_server_add_insecure_http2_port(server, addr.as_ptr() as _) as u16
        }
    }
}

use self::imp::Binder;

/// Service configuration struct.
///
/// Use it to build a service which can be registered to a server.
pub struct ServiceBuilder {
    handlers: HashMap<&'static [u8], Handler>,
}

impl ServiceBuilder {
    pub fn new() -> ServiceBuilder {
        ServiceBuilder {
            handlers: HashMap::new(),
        }
    }

    /// Add a unary rpc call handler.
    pub fn add_unary_handler<P, Q, F>(mut self, method: &Method<P, Q>, handler: F) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, P, UnarySink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, payload: &[u8]| {
            execute_unary(ctx, ser, de, payload, &handler)
        });
        self.handlers
            .insert(method.name.as_bytes(), Handler::new(MethodType::Unary, h));
        self
    }

    /// Add a client streaming rpc call handler.
    pub fn add_client_streaming_handler<P, Q, F>(
        mut self,
        method: &Method<P, Q>,
        handler: F,
    ) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, RequestStream<P>, ClientStreamingSink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, _: &[u8]| {
            execute_client_streaming(ctx, ser, de, &handler)
        });
        self.handlers.insert(
            method.name.as_bytes(),
            Handler::new(MethodType::ClientStreaming, h),
        );
        self
    }

    /// Add a server streaming rpc call handler.
    pub fn add_server_streaming_handler<P, Q, F>(
        mut self,
        method: &Method<P, Q>,
        handler: F,
    ) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, P, ServerStreamingSink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, payload: &[u8]| {
            execute_server_streaming(ctx, ser, de, payload, &handler)
        });
        self.handlers.insert(
            method.name.as_bytes(),
            Handler::new(MethodType::ServerStreaming, h),
        );
        self
    }

    /// Add a duplex streaming rpc call handler.
    pub fn add_duplex_streaming_handler<P, Q, F>(
        mut self,
        method: &Method<P, Q>,
        handler: F,
    ) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, RequestStream<P>, DuplexSink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, _: &[u8]| {
            execute_duplex_streaming(ctx, ser, de, &handler)
        });
        self.handlers
            .insert(method.name.as_bytes(), Handler::new(MethodType::Duplex, h));
        self
    }

    pub fn build(self) -> Service {
        Service {
            handlers: self.handlers,
        }
    }
}

pub struct Service {
    handlers: HashMap<&'static [u8], Handler>,
}

/// Server configuration struct.
pub struct ServerBuilder {
    env: Arc<Environment>,
    binders: Vec<Binder>,
    args: Option<ChannelArgs>,
    slots_per_cq: usize,
    handlers: HashMap<&'static [u8], Handler>,
}

impl ServerBuilder {
    pub fn new(env: Arc<Environment>) -> ServerBuilder {
        ServerBuilder {
            env: env,
            binders: Vec::new(),
            args: None,
            slots_per_cq: DEFAULT_REQUEST_SLOTS_PER_CQ,
            handlers: HashMap::new(),
        }
    }

    /// Bind to an address.
    ///
    /// This function can be called multiple times.
    pub fn bind<S: Into<String>>(mut self, host: S, port: u16) -> ServerBuilder {
        self.binders.push(Binder::new(host.into(), port));
        self
    }

    /// Add additional configuration for each incoming channel.
    pub fn channel_args(mut self, args: ChannelArgs) -> ServerBuilder {
        self.args = Some(args);
        self
    }

    /// Set how many requests a completion queue can handle.
    pub fn requests_slot_per_cq(mut self, slots: usize) -> ServerBuilder {
        self.slots_per_cq = slots;
        self
    }

    /// Register a service.
    pub fn register_service(mut self, service: Service) -> ServerBuilder {
        self.handlers.extend(service.handlers);
        self
    }

    pub fn build(mut self) -> Result<Server> {
        let args = self.args
            .as_ref()
            .map_or_else(ptr::null, |args| args.as_ptr());
        unsafe {
            let server = grpc_sys::grpc_server_create(args, ptr::null_mut());
            let mut bind_addrs = Vec::with_capacity(self.binders.len());
            for mut binder in self.binders.drain(..) {
                let bind_port = binder.bind(server);
                if bind_port == 0 {
                    grpc_sys::grpc_server_destroy(server);
                    return Err(Error::BindFail(binder.host, binder.port));
                }

                bind_addrs.push((binder.host, bind_port as u16));
            }

            for cq in self.env.completion_queues() {
                grpc_sys::grpc_server_register_completion_queue(
                    server,
                    cq.as_ptr(),
                    ptr::null_mut(),
                );
            }

            Ok(Server {
                inner: Arc::new(Inner {
                    env: self.env,
                    server: server,
                    shutdown: AtomicBool::new(false),
                    bind_addrs: bind_addrs,
                    slots_per_cq: self.slots_per_cq,
                    handlers: self.handlers,
                }),
            })
        }
    }
}

#[cfg(feature = "secure")]
mod secure_server {
    use credentials::ServerCredentials;

    use super::{Binder, ServerBuilder};

    impl ServerBuilder {
        /// Bind to an address for secure connection.
        ///
        /// This function can be called multiple times.
        pub fn bind_secure<S: Into<String>>(
            mut self,
            host: S,
            port: u16,
            c: ServerCredentials,
        ) -> ServerBuilder {
            self.binders.push(Binder::with_cred(host.into(), port, c));
            self
        }
    }
}

pub struct Inner {
    env: Arc<Environment>,
    server: *mut GrpcServer,
    bind_addrs: Vec<(String, u16)>,
    slots_per_cq: usize,
    shutdown: AtomicBool,
    handlers: HashMap<&'static [u8], Handler>,
}

impl Inner {
    /// Get the handler for the requested method path.
    pub fn get_handler(&self, method: &[u8]) -> Option<&Handler> {
        self.handlers.get(method)
    }
}

impl Drop for Inner {
    fn drop(&mut self) {
        unsafe { grpc_sys::grpc_server_destroy(self.server) }
    }
}

/// Request notification of a new call.
pub fn request_call(inner: Arc<Inner>, cq: &CompletionQueue) {
    if inner.shutdown.load(Ordering::Relaxed) {
        return;
    }
    let server_ptr = inner.server;
    let prom = CallTag::request(inner);
    let request_ptr = prom.request_ctx().unwrap().as_ptr();
    let prom_box = Box::new(prom);
    let tag = Box::into_raw(prom_box);
    let code = unsafe {
        grpc_sys::grpcwrap_server_request_call(server_ptr, cq.as_ptr(), request_ptr, tag as *mut _)
    };
    if code != GrpcCallStatus::Ok {
        Box::from(tag);
        panic!("failed to request call: {:?}", code);
    }
}

/// An asynchronize shutdown future.
pub struct ShutdownFuture {
    cq_f: CqFuture<()>,
}

impl Future for ShutdownFuture {
    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> Poll<(), Error> {
        try_ready!(self.cq_f.poll());
        Ok(Async::Ready(()))
    }
}

// It's safe to request call simultaneously.
unsafe impl Sync for Inner {}
unsafe impl Send for Inner {}

pub struct Server {
    inner: Arc<Inner>,
}

impl Server {
    /// Shutdown the server asynchronously.
    pub fn shutdown(&mut self) -> ShutdownFuture {
        let (cq_f, prom) = CallTag::shutdown_pair();
        let prom_box = Box::new(prom);
        let tag = Box::into_raw(prom_box);
        unsafe {
            let cq_ptr = self.inner.env.completion_queues()[0].as_ptr();
            grpc_sys::grpc_server_shutdown_and_notify(self.inner.server, cq_ptr, tag as *mut _)
        }
        self.inner.shutdown.store(true, Ordering::SeqCst);
        ShutdownFuture { cq_f: cq_f }
    }

    /// Cancel all in-progress calls.
    ///
    /// Only usable after shutdown.
    pub fn cancel_all_calls(&mut self) {
        unsafe { grpc_sys::grpc_server_cancel_all_calls(self.inner.server) }
    }

    /// Start a server.
    ///
    /// Tells all listeners to start listening.
    pub fn start(&mut self) {
        unsafe {
            grpc_sys::grpc_server_start(self.inner.server);
            for cq in self.inner.env.completion_queues() {
                for _ in 0..self.inner.slots_per_cq {
                    request_call(self.inner.clone(), cq);
                }
            }
        }
    }

    /// Get the binded addresses.
    pub fn bind_addrs(&self) -> &[(String, u16)] {
        &self.inner.bind_addrs
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        // if the server is not shutdown completely, destroy a server will core.
        // TODO: don't wait here
        let f = self.shutdown();
        self.cancel_all_calls();
        let _ = f.wait();
    }
}
<commit_msg>Implementing the Debug trait for Server, required when one wants to calls unwrap_err on a Result<Server, Error> (#116)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::fmt;
use std::fmt::{Formatter, Debug};

use futures::{Async, Future, Poll};
use grpc_sys::{self, GrpcCallStatus, GrpcServer};

use RpcContext;
use async::{CallTag, CqFuture};
use call::{Method, MethodType};
use call::server::*;
use channel::ChannelArgs;
use cq::CompletionQueue;
use env::Environment;
use error::{Error, Result};

const DEFAULT_REQUEST_SLOTS_PER_CQ: usize = 1024;

pub type CallBack = Box<Fn(RpcContext, &[u8])>;

/// Handler is an rpc call holder.
pub struct Handler {
    method_type: MethodType,
    cb: CallBack,
}

impl Handler {
    pub fn new(method_type: MethodType, cb: CallBack) -> Handler {
        Handler {
            method_type: method_type,
            cb: cb,
        }
    }

    pub fn cb(&self) -> &CallBack {
        &self.cb
    }

    pub fn method_type(&self) -> MethodType {
        self.method_type
    }
}

#[cfg(feature = "secure")]
mod imp {
    use grpc_sys::{self, GrpcServer};

    use credentials::ServerCredentials;

    pub struct Binder {
        pub host: String,
        pub port: u16,
        cred: Option<ServerCredentials>,
    }

    impl Binder {
        pub fn new(host: String, port: u16) -> Binder {
            let cred = None;
            Binder { host, port, cred }
        }

        pub fn with_cred(host: String, port: u16, cred: ServerCredentials) -> Binder {
            let cred = Some(cred);
            Binder { host, port, cred }
        }

        pub unsafe fn bind(&mut self, server: *mut GrpcServer) -> u16 {
            let addr = format!("{}:{}\0", self.host, self.port);
            let port = match self.cred.take() {
                None => grpc_sys::grpc_server_add_insecure_http2_port(server, addr.as_ptr() as _),
                Some(mut cert) => grpc_sys::grpc_server_add_secure_http2_port(server, addr.as_ptr() as _, cert.as_mut_ptr())
            };
            port as u16
        }
    }
}

#[cfg(not(feature = "secure"))]
mod imp {
    use grpc_sys::{self, GrpcServer};

    pub struct Binder {
        pub host: String,
        pub port: u16,
    }

    impl Binder {
        pub fn new(host: String, port: u16) -> Binder {
            Binder { host, port }
        }

        pub unsafe fn bind(&self, server: *mut GrpcServer) -> u16 {
            let addr = format!("{}:{}\0", self.host, self.port);
            grpc_sys::grpc_server_add_insecure_http2_port(server, addr.as_ptr() as _) as u16
        }
    }
}

use self::imp::Binder;

/// Service configuration struct.
///
/// Use it to build a service which can be registered to a server.
pub struct ServiceBuilder {
    handlers: HashMap<&'static [u8], Handler>,
}

impl ServiceBuilder {
    pub fn new() -> ServiceBuilder {
        ServiceBuilder {
            handlers: HashMap::new(),
        }
    }

    /// Add a unary rpc call handler.
    pub fn add_unary_handler<P, Q, F>(mut self, method: &Method<P, Q>, handler: F) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, P, UnarySink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, payload: &[u8]| {
            execute_unary(ctx, ser, de, payload, &handler)
        });
        self.handlers
            .insert(method.name.as_bytes(), Handler::new(MethodType::Unary, h));
        self
    }

    /// Add a client streaming rpc call handler.
    pub fn add_client_streaming_handler<P, Q, F>(
        mut self,
        method: &Method<P, Q>,
        handler: F,
    ) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, RequestStream<P>, ClientStreamingSink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, _: &[u8]| {
            execute_client_streaming(ctx, ser, de, &handler)
        });
        self.handlers.insert(
            method.name.as_bytes(),
            Handler::new(MethodType::ClientStreaming, h),
        );
        self
    }

    /// Add a server streaming rpc call handler.
    pub fn add_server_streaming_handler<P, Q, F>(
        mut self,
        method: &Method<P, Q>,
        handler: F,
    ) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, P, ServerStreamingSink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, payload: &[u8]| {
            execute_server_streaming(ctx, ser, de, payload, &handler)
        });
        self.handlers.insert(
            method.name.as_bytes(),
            Handler::new(MethodType::ServerStreaming, h),
        );
        self
    }

    /// Add a duplex streaming rpc call handler.
    pub fn add_duplex_streaming_handler<P, Q, F>(
        mut self,
        method: &Method<P, Q>,
        handler: F,
    ) -> ServiceBuilder
    where
        P: 'static,
        Q: 'static,
        F: Fn(RpcContext, RequestStream<P>, DuplexSink<Q>) + 'static,
    {
        let (ser, de) = (method.resp_ser(), method.req_de());
        let h = Box::new(move |ctx: RpcContext, _: &[u8]| {
            execute_duplex_streaming(ctx, ser, de, &handler)
        });
        self.handlers
            .insert(method.name.as_bytes(), Handler::new(MethodType::Duplex, h));
        self
    }

    pub fn build(self) -> Service {
        Service {
            handlers: self.handlers,
        }
    }
}

pub struct Service {
    handlers: HashMap<&'static [u8], Handler>,
}

/// Server configuration struct.
pub struct ServerBuilder {
    env: Arc<Environment>,
    binders: Vec<Binder>,
    args: Option<ChannelArgs>,
    slots_per_cq: usize,
    handlers: HashMap<&'static [u8], Handler>,
}

impl ServerBuilder {
    pub fn new(env: Arc<Environment>) -> ServerBuilder {
        ServerBuilder {
            env: env,
            binders: Vec::new(),
            args: None,
            slots_per_cq: DEFAULT_REQUEST_SLOTS_PER_CQ,
            handlers: HashMap::new(),
        }
    }

    /// Bind to an address.
    ///
    /// This function can be called multiple times.
    pub fn bind<S: Into<String>>(mut self, host: S, port: u16) -> ServerBuilder {
        self.binders.push(Binder::new(host.into(), port));
        self
    }

    /// Add additional configuration for each incoming channel.
    pub fn channel_args(mut self, args: ChannelArgs) -> ServerBuilder {
        self.args = Some(args);
        self
    }

    /// Set how many requests a completion queue can handle.
    pub fn requests_slot_per_cq(mut self, slots: usize) -> ServerBuilder {
        self.slots_per_cq = slots;
        self
    }

    /// Register a service.
    pub fn register_service(mut self, service: Service) -> ServerBuilder {
        self.handlers.extend(service.handlers);
        self
    }

    pub fn build(mut self) -> Result<Server> {
        let args = self.args
            .as_ref()
            .map_or_else(ptr::null, |args| args.as_ptr());
        unsafe {
            let server = grpc_sys::grpc_server_create(args, ptr::null_mut());
            let mut bind_addrs = Vec::with_capacity(self.binders.len());
            for mut binder in self.binders.drain(..) {
                let bind_port = binder.bind(server);
                if bind_port == 0 {
                    grpc_sys::grpc_server_destroy(server);
                    return Err(Error::BindFail(binder.host, binder.port));
                }

                bind_addrs.push((binder.host, bind_port as u16));
            }

            for cq in self.env.completion_queues() {
                grpc_sys::grpc_server_register_completion_queue(
                    server,
                    cq.as_ptr(),
                    ptr::null_mut(),
                );
            }

            Ok(Server {
                inner: Arc::new(Inner {
                    env: self.env,
                    server: server,
                    shutdown: AtomicBool::new(false),
                    bind_addrs: bind_addrs,
                    slots_per_cq: self.slots_per_cq,
                    handlers: self.handlers,
                }),
            })
        }
    }
}

#[cfg(feature = "secure")]
mod secure_server {
    use credentials::ServerCredentials;

    use super::{Binder, ServerBuilder};

    impl ServerBuilder {
        /// Bind to an address for secure connection.
        ///
        /// This function can be called multiple times.
        pub fn bind_secure<S: Into<String>>(
            mut self,
            host: S,
            port: u16,
            c: ServerCredentials,
        ) -> ServerBuilder {
            self.binders.push(Binder::with_cred(host.into(), port, c));
            self
        }
    }
}

pub struct Inner {
    env: Arc<Environment>,
    server: *mut GrpcServer,
    bind_addrs: Vec<(String, u16)>,
    slots_per_cq: usize,
    shutdown: AtomicBool,
    handlers: HashMap<&'static [u8], Handler>,
}

impl Inner {
    /// Get the handler for the requested method path.
    pub fn get_handler(&self, method: &[u8]) -> Option<&Handler> {
        self.handlers.get(method)
    }
}

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

impl Drop for Inner {
    fn drop(&mut self) {
        unsafe { grpc_sys::grpc_server_destroy(self.server) }
    }
}

/// Request notification of a new call.
pub fn request_call(inner: Arc<Inner>, cq: &CompletionQueue) {
    if inner.shutdown.load(Ordering::Relaxed) {
        return;
    }
    let server_ptr = inner.server;
    let prom = CallTag::request(inner);
    let request_ptr = prom.request_ctx().unwrap().as_ptr();
    let prom_box = Box::new(prom);
    let tag = Box::into_raw(prom_box);
    let code = unsafe {
        grpc_sys::grpcwrap_server_request_call(server_ptr, cq.as_ptr(), request_ptr, tag as *mut _)
    };
    if code != GrpcCallStatus::Ok {
        Box::from(tag);
        panic!("failed to request call: {:?}", code);
    }
}

/// An asynchronize shutdown future.
pub struct ShutdownFuture {
    cq_f: CqFuture<()>,
}

impl Future for ShutdownFuture {
    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> Poll<(), Error> {
        try_ready!(self.cq_f.poll());
        Ok(Async::Ready(()))
    }
}

// It's safe to request call simultaneously.
unsafe impl Sync for Inner {}
unsafe impl Send for Inner {}

pub struct Server {
    inner: Arc<Inner>,
}

impl Server {
    /// Shutdown the server asynchronously.
    pub fn shutdown(&mut self) -> ShutdownFuture {
        let (cq_f, prom) = CallTag::shutdown_pair();
        let prom_box = Box::new(prom);
        let tag = Box::into_raw(prom_box);
        unsafe {
            let cq_ptr = self.inner.env.completion_queues()[0].as_ptr();
            grpc_sys::grpc_server_shutdown_and_notify(self.inner.server, cq_ptr, tag as *mut _)
        }
        self.inner.shutdown.store(true, Ordering::SeqCst);
        ShutdownFuture { cq_f: cq_f }
    }

    /// Cancel all in-progress calls.
    ///
    /// Only usable after shutdown.
    pub fn cancel_all_calls(&mut self) {
        unsafe { grpc_sys::grpc_server_cancel_all_calls(self.inner.server) }
    }

    /// Start a server.
    ///
    /// Tells all listeners to start listening.
    pub fn start(&mut self) {
        unsafe {
            grpc_sys::grpc_server_start(self.inner.server);
            for cq in self.inner.env.completion_queues() {
                for _ in 0..self.inner.slots_per_cq {
                    request_call(self.inner.clone(), cq);
                }
            }
        }
    }

    /// Get the binded addresses.
    pub fn bind_addrs(&self) -> &[(String, u16)] {
        &self.inner.bind_addrs
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        // if the server is not shutdown completely, destroy a server will core.
        // TODO: don't wait here
        let f = self.shutdown();
        self.cancel_all_calls();
        let _ = f.wait();
    }
}

impl Debug for Server {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{:?}", self.inner)
    }
}<|endoftext|>


<commit_before>extern crate piston;
extern crate string_telephone;
extern crate collections;

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket, Command, PacketDisconnect, PacketConnect};
use std::fmt;

struct Player {
    controller: SocketAddr,
    x: i32,
    y: i32,

    keyUp: bool,
    keyDown: bool,
    keyLeft: bool,
    keyRight: bool
}

impl Player {
    pub fn new (controller: SocketAddr, x: i32, y: i32) -> Player {
        Player {
            controller: controller,
            x: x,
            y: y,
            keyUp: false,
            keyDown: false,
            keyLeft: false,
            keyRight: false
        }
    }

    pub fn move(&mut self) {
        if self.keyUp && self.y > 0 {
            self.y -= 1;
        } else if self.keyDown && self.y < 600 {
            self.y += 1;
        }

        if self.keyLeft && self.x > 0 {
            self.x -= 1;
        } else if self.keyRight && self.x < 800{
            self.x += 1;
        }
    }
}

impl fmt::Show for Player {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} at {} {}", self.controller, self.x, self.y)
    }
}

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    let mut players:Vec<Player> = vec![
        Player::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, 400, 300)
    ];

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        match e {
            piston::Update(update_args) => {
                loop {
                    match server.poll() {
                        Some((Command(PacketConnect), addr_from)) => {
                            //New player!
                        },
                        Some((Command(PacketDisconnect), addr_from)) => {
                            //Ohnoes
                        },
                        Some((UserPacket(packet), _)) => {
                            //Do something
                        },
                        Some(_) => (),
                        None => break
                    }
                };

                //Update the game world
                for player in players.iter_mut() {
                    player.move()
                }
                println!("{}", players);
                let culled = server.cull();
                if culled.len() > 0 {
                    println!("{}", culled);
                }
            },
            _ => ()
        }
    }
}
<commit_msg>Connect/disconnect adding players to the world<commit_after>extern crate piston;
extern crate string_telephone;
extern crate collections;

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket, Command, PacketDisconnect, PacketConnect};
use std::fmt;
use std::rand;
use std::rand::Rng;

struct Player {
    controller: SocketAddr,
    x: i32,
    y: i32,

    keyUp: bool,
    keyDown: bool,
    keyLeft: bool,
    keyRight: bool
}

impl Player {
    pub fn new (controller: SocketAddr, x: i32, y: i32) -> Player {
        Player {
            controller: controller,
            x: x,
            y: y,
            keyUp: false,
            keyDown: false,
            keyLeft: false,
            keyRight: false
        }
    }

    pub fn move(&mut self) {
        if self.keyUp && self.y > 0 {
            self.y -= 1;
        } else if self.keyDown && self.y < 600 {
            self.y += 1;
        }

        if self.keyLeft && self.x > 0 {
            self.x -= 1;
        } else if self.keyRight && self.x < 800{
            self.x += 1;
        }
    }
}

impl fmt::Show for Player {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} at {} {}", self.controller, self.x, self.y)
    }
}

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    let mut players:Vec<Player> = vec![];
    let mut rng = rand::task_rng();

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        match e {
            piston::Update(update_args) => {
                loop {
                    match server.poll() {
                        Some((Command(PacketConnect), addr_from)) => {
                            players.push(Player::new(addr_from, rng.gen::<uint>() as i32 % 800, rng.gen::<uint>() as i32 % 600));
                        },
                        Some((Command(PacketDisconnect), addr_from)) => {
                            players = players.into_iter().filter(|&player| &player.controller != &addr_from).collect()
                        },
                        Some((UserPacket(packet), _)) => {
                            //Do something
                        },
                        Some(_) => (),
                        None => break
                    }
                };

                //Update the game world
                for player in players.iter_mut() {
                    player.move()
                }

                let culled = server.cull();
                if culled.len() > 0 {
                    players = players.into_iter().filter(|&player| culled.contains(&player.controller) == false).collect()
                }
            },
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>//! Iron web server that serves the API.
use diesel::migrations::run_pending_migrations;
use hyper::server::Listening;
use iron::{Chain, Handler, Iron};
use iron::error::HttpResult;
use mount::Mount;
use persistent::{Read, Write};
use r2d2::{Config as R2D2Config, Pool};
use r2d2_diesel::ConnectionManager;
use router::Router;

use api::r0::registration::Register;
use api::r0::versions::Versions;
use config::FinalConfig;
use error::CLIError;
use db::DB;

/// Ruma's web server.
pub struct Server<'a, T> where T: Handler {
    config: &'a FinalConfig,
    iron: Iron<T>,
}

impl<'a> Server<'a, Mount> {
    /// Create a new `Server` from a `FinalConfig`.
    pub fn new(config: &FinalConfig) -> Result<Server<Mount>, CLIError> {
        let mut router = Router::new();

        router.post("/register", Register::chain());

        let mut chain = Chain::new(router);

        debug!("Connecting to PostgreSQL.");
        let r2d2_config = R2D2Config::default();
        let connection_manager = ConnectionManager::new(&config.postgres_url[..]);
        let connection_pool = try!(Pool::new(r2d2_config, connection_manager));
        let connection = try!(connection_pool.get());

        debug!("Running pending migrations.");
        match run_pending_migrations(&*connection) {
            Ok(_) => {},
            Err(error) => return Err(CLIError::new(format!("{:?}", error))),
        }

        chain.link_before(Read::<FinalConfig>::one(config.clone()));
        chain.link_before(Write::<DB>::one(connection_pool));

        let mut versions = Router::new();
        versions.get("/versions", Versions::new(vec!["r0.0.1"]));

        let mut mount = Mount::new();

        mount.mount("/_matrix/client/", versions);
        mount.mount("/_matrix/client/r0/", chain);

        Ok(Server {
            config: config,
            iron: Iron::new(mount),
        })
    }

    /// Start the server and block the current thread until stopped or interrupted.
    pub fn start(self) -> HttpResult<Listening> {
        let address = format!("{}:{}", self.config.bind_address, self.config.bind_port);

        info!("Starting Ruma server on {}.", address);

        self.iron.http(&address[..])
    }
}
<commit_msg>Rename chain to r0 to make it more clear what it is.<commit_after>//! Iron web server that serves the API.
use diesel::migrations::run_pending_migrations;
use hyper::server::Listening;
use iron::{Chain, Handler, Iron};
use iron::error::HttpResult;
use mount::Mount;
use persistent::{Read, Write};
use r2d2::{Config as R2D2Config, Pool};
use r2d2_diesel::ConnectionManager;
use router::Router;

use api::r0::registration::Register;
use api::r0::versions::Versions;
use config::FinalConfig;
use error::CLIError;
use db::DB;

/// Ruma's web server.
pub struct Server<'a, T> where T: Handler {
    config: &'a FinalConfig,
    iron: Iron<T>,
}

impl<'a> Server<'a, Mount> {
    /// Create a new `Server` from a `FinalConfig`.
    pub fn new(config: &FinalConfig) -> Result<Server<Mount>, CLIError> {
        let mut router = Router::new();

        router.post("/register", Register::chain());

        let mut r0 = Chain::new(router);

        debug!("Connecting to PostgreSQL.");
        let r2d2_config = R2D2Config::default();
        let connection_manager = ConnectionManager::new(&config.postgres_url[..]);
        let connection_pool = try!(Pool::new(r2d2_config, connection_manager));
        let connection = try!(connection_pool.get());

        debug!("Running pending migrations.");
        match run_pending_migrations(&*connection) {
            Ok(_) => {},
            Err(error) => return Err(CLIError::new(format!("{:?}", error))),
        }

        r0.link_before(Read::<FinalConfig>::one(config.clone()));
        r0.link_before(Write::<DB>::one(connection_pool));

        let mut versions = Router::new();
        versions.get("/versions", Versions::new(vec!["r0.0.1"]));

        let mut mount = Mount::new();

        mount.mount("/_matrix/client/", versions);
        mount.mount("/_matrix/client/r0/", r0);

        Ok(Server {
            config: config,
            iron: Iron::new(mount),
        })
    }

    /// Start the server and block the current thread until stopped or interrupted.
    pub fn start(self) -> HttpResult<Listening> {
        let address = format!("{}:{}", self.config.bind_address, self.config.bind_port);

        info!("Starting Ruma server on {}.", address);

        self.iron.http(&address[..])
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;

use bytes::Bytes;

use httpbis::HttpError;
use httpbis::Header;
use httpbis::Headers;
use httpbis::server::HttpServer;
use httpbis::server::ServerTlsOption;

use futures::Future;
use futures::stream;
use futures::stream::Stream;

use method::*;
use error::*;
use futures_grpc::*;
use httpbis::futures_misc::*;
use grpc::*;
use grpc_frame::*;
use httpbis::http_common::*;
use httpbis::server_conf::*;
use httpbis::misc::any_to_string;
use req::GrpcRequestOptions;
use resp::*;
use metadata::GrpcMetadata;

pub trait MethodHandler<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> GrpcStreamingFlavor for MethodHandlerUnary<F> {
    type Flavor = GrpcStreamingUnary;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Unary
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerClientStreaming<F> {
    type Flavor = GrpcStreamingClientStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ClientStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerServerStreaming<F> {
    type Flavor = GrpcStreamingServerStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ServerStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerBidi<F> {
    type Flavor = GrpcStreamingBidi;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Bidi
    }
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcSingleResponse(
            Box::new(stream_single(req)
                .and_then(move |req| f(m, req).0)))
                    .into_stream()
    }
}

impl<Req : Send + 'static, Resp : Send + 'static, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        ((self.f)(m, req)).into_stream()
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, o: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcStreamingResponse(Box::new(
            stream_single(req)
                .and_then(move |req| f(o, req).0)))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        (self.f)(m, req)
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, m: GrpcRequestOptions, grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>;
}

struct MethodHandlerDispatchImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, o: GrpcRequestOptions, req_grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(o, Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                resp.and_then_items(move |resp| {
                    desc_copy.resp_marshaller.write(&resp)
                })
            }
            Err(e) => {
                let message = any_to_string(e);
                GrpcStreamingResponse::err(GrpcError::Panic(message))
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    /// Join multiple service definitions into one
    pub fn join<I>(iter: I) -> ServerServiceDefinition
        where I : IntoIterator<Item=ServerServiceDefinition>
    {
        ServerServiceDefinition {
            methods: iter.into_iter().flat_map(|s| s.methods).collect()
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    pub fn handle_method(&self, name: &str, o: GrpcRequestOptions, message: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        self.find_method(name).dispatch.start_request(o, message)
    }
}

#[derive(Default, Debug, Clone)]
pub struct GrpcServerConf {
    pub http: HttpServerConf,
}

pub struct GrpcServer {
    server: HttpServer,
}

impl GrpcServer {
    pub fn new_plain<A : ToSocketAddrs>(
        addr: A,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        GrpcServer::new(addr, ServerTlsOption::Plain, conf, service_definition)
    }

    pub fn new<A : ToSocketAddrs>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        let mut conf = conf;
        conf.http.thread_name =
            Some(conf.http.thread_name.unwrap_or_else(|| "grpc-server-loop".to_owned()));

        let service_definition = Arc::new(service_definition);
        GrpcServer {
            server: HttpServer::new(addr, tls, conf.http, GrpcHttpServerHandlerFactory {
                service_definition: service_definition.clone(),
            })
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        self.server.local_addr()
    }

    pub fn is_alive(&self) -> bool {
        self.server.is_alive()
    }
}

struct GrpcHttpServerHandlerFactory {
    service_definition: Arc<ServerServiceDefinition>,
}

fn stream_500(message: &str) -> HttpResponse {
    // TODO: HttpResponse::headers
    HttpResponse::from_stream(stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ])))))
}

impl HttpService for GrpcHttpServerHandlerFactory {
    fn new_request(&self, headers: Headers, req: HttpPartFutureStreamSend) -> HttpResponse {

        let path = match headers.get_opt(":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        let metadata = match GrpcMetadata::from_headers(headers) {
            Ok(metadata) => metadata,
            Err(_) => return stream_500("decode metadata error"),
        };

        // TODO: catch unwind
        let grpc_response = self.service_definition.handle_method(
            &path,
            GrpcRequestOptions { metadata: metadata },
            Box::new(grpc_request));

        HttpResponse::new(grpc_response.0.map_err(HttpError::from).map(|(metadata, grpc_frames)| {
            let mut init_headers = Headers(vec![
                Header::new(":status", "200"),
                Header::new("content-type", "application/grpc"),
            ]);

            init_headers.extend(metadata.into_headers());

            let s2 = grpc_frames
                .map(|frame| HttpStreamPart::intermediate_data(Bytes::from(write_grpc_frame_to_vec(&frame))))
                .then(|result| {
                    match result {
                        Ok(part) => {
                            let r: Result<_, HttpError> = Ok(part);
                            r
                        }
                        Err(e) =>
                            Ok(HttpStreamPart::last_headers(
                                match e {
                                    GrpcError::GrpcMessage(GrpcMessageError { grpc_status, grpc_message }) => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            // TODO: check nonzero
                                            Header::new(HEADER_GRPC_STATUS, format!("{}", grpc_status)),
                                            // TODO: escape invalid
                                            Header::new(HEADER_GRPC_MESSAGE, grpc_message),
                                        ])
                                    }
                                    e => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                                        ])
                                    }
                                }
                            ))
                    }
                })
                .map_err(HttpError::from);

            let s3 = stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
                Header::new(HEADER_GRPC_STATUS, "0"),
            ]))));

            let http_parts: HttpPartFutureStreamSend = Box::new(s2.chain(s3));

            (init_headers, http_parts)
        }))
    }
}
<commit_msg>Better type name<commit_after>use std::sync::Arc;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;

use bytes::Bytes;

use httpbis::HttpError;
use httpbis::Header;
use httpbis::Headers;
use httpbis::server::HttpServer;
use httpbis::server::ServerTlsOption;

use futures::Future;
use futures::stream;
use futures::stream::Stream;

use method::*;
use error::*;
use futures_grpc::*;
use httpbis::futures_misc::*;
use grpc::*;
use grpc_frame::*;
use httpbis::http_common::*;
use httpbis::server_conf::*;
use httpbis::misc::any_to_string;
use req::GrpcRequestOptions;
use resp::*;
use metadata::GrpcMetadata;

pub trait MethodHandler<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> GrpcStreamingFlavor for MethodHandlerUnary<F> {
    type Flavor = GrpcStreamingUnary;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Unary
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerClientStreaming<F> {
    type Flavor = GrpcStreamingClientStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ClientStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerServerStreaming<F> {
    type Flavor = GrpcStreamingServerStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ServerStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerBidi<F> {
    type Flavor = GrpcStreamingBidi;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Bidi
    }
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcSingleResponse(
            Box::new(stream_single(req)
                .and_then(move |req| f(m, req).0)))
                    .into_stream()
    }
}

impl<Req : Send + 'static, Resp : Send + 'static, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        ((self.f)(m, req)).into_stream()
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, o: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcStreamingResponse(Box::new(
            stream_single(req)
                .and_then(move |req| f(o, req).0)))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        (self.f)(m, req)
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, m: GrpcRequestOptions, grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>;
}

struct MethodHandlerDispatchImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, o: GrpcRequestOptions, req_grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(o, Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                resp.and_then_items(move |resp| {
                    desc_copy.resp_marshaller.write(&resp)
                })
            }
            Err(e) => {
                let message = any_to_string(e);
                GrpcStreamingResponse::err(GrpcError::Panic(message))
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    /// Join multiple service definitions into one
    pub fn join<I>(iter: I) -> ServerServiceDefinition
        where I : IntoIterator<Item=ServerServiceDefinition>
    {
        ServerServiceDefinition {
            methods: iter.into_iter().flat_map(|s| s.methods).collect()
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    pub fn handle_method(&self, name: &str, o: GrpcRequestOptions, message: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        self.find_method(name).dispatch.start_request(o, message)
    }
}

#[derive(Default, Debug, Clone)]
pub struct GrpcServerConf {
    pub http: HttpServerConf,
}

pub struct GrpcServer {
    server: HttpServer,
}

impl GrpcServer {
    pub fn new_plain<A : ToSocketAddrs>(
        addr: A,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        GrpcServer::new(addr, ServerTlsOption::Plain, conf, service_definition)
    }

    pub fn new<A : ToSocketAddrs>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        let mut conf = conf;
        conf.http.thread_name =
            Some(conf.http.thread_name.unwrap_or_else(|| "grpc-server-loop".to_owned()));

        let service_definition = Arc::new(service_definition);
        GrpcServer {
            server: HttpServer::new(addr, tls, conf.http, GrpcHttpService {
                service_definition: service_definition.clone(),
            })
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        self.server.local_addr()
    }

    pub fn is_alive(&self) -> bool {
        self.server.is_alive()
    }
}

struct GrpcHttpService {
    service_definition: Arc<ServerServiceDefinition>,
}

fn stream_500(message: &str) -> HttpResponse {
    // TODO: HttpResponse::headers
    HttpResponse::from_stream(stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ])))))
}

impl HttpService for GrpcHttpService {
    fn new_request(&self, headers: Headers, req: HttpPartFutureStreamSend) -> HttpResponse {

        let path = match headers.get_opt(":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        let metadata = match GrpcMetadata::from_headers(headers) {
            Ok(metadata) => metadata,
            Err(_) => return stream_500("decode metadata error"),
        };

        // TODO: catch unwind
        let grpc_response = self.service_definition.handle_method(
            &path,
            GrpcRequestOptions { metadata: metadata },
            Box::new(grpc_request));

        HttpResponse::new(grpc_response.0.map_err(HttpError::from).map(|(metadata, grpc_frames)| {
            let mut init_headers = Headers(vec![
                Header::new(":status", "200"),
                Header::new("content-type", "application/grpc"),
            ]);

            init_headers.extend(metadata.into_headers());

            let s2 = grpc_frames
                .map(|frame| HttpStreamPart::intermediate_data(Bytes::from(write_grpc_frame_to_vec(&frame))))
                .then(|result| {
                    match result {
                        Ok(part) => {
                            let r: Result<_, HttpError> = Ok(part);
                            r
                        }
                        Err(e) =>
                            Ok(HttpStreamPart::last_headers(
                                match e {
                                    GrpcError::GrpcMessage(GrpcMessageError { grpc_status, grpc_message }) => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            // TODO: check nonzero
                                            Header::new(HEADER_GRPC_STATUS, format!("{}", grpc_status)),
                                            // TODO: escape invalid
                                            Header::new(HEADER_GRPC_MESSAGE, grpc_message),
                                        ])
                                    }
                                    e => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                                        ])
                                    }
                                }
                            ))
                    }
                })
                .map_err(HttpError::from);

            let s3 = stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
                Header::new(HEADER_GRPC_STATUS, "0"),
            ]))));

            let http_parts: HttpPartFutureStreamSend = Box::new(s2.chain(s3));

            (init_headers, http_parts)
        }))
    }
}
<|endoftext|>


<commit_before>use iron::{Middleware, Request, Response, Alloy};
use iron::middleware::Status;
use std::sync::Arc;

/// `Middleware` implementing this trait can be linked using `Shared` so that
/// they are not cloned for each request. This can vastly improve performance
/// for immutable middleware that are not modified while handling requests.
pub trait ShareableMiddleware {
    /// `shared_enter` is an immutable version of `enter` from the `Middleware`
    /// trait - it receives an & reference to self rather than an &mut
    /// reference.
    fn shared_enter(&self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status;

    /// `shared_exit` is an immutable version of `exit` from the `Middleware`
    /// trait - it receives an & reference to self rather than an &mut
    /// reference.
    fn shared_exit(&self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status;
}

/// `Shared` is used to wrap `ShareableMiddleware` into `Middleware` so they
/// can be linked onto a `Chain` while still avoiding unnecessary copies.
pub struct Shared {
    /// The wrapped `ShareableMiddleware`
    pub middleware: Arc<Box<ShareableMiddleware + Send + Share>>
}

impl Shared {
    /// Creates a new instance of `Shared` containing the provided
    /// `ShareableMiddleware` and allowing it to be used as `Middleware`.
    pub fn new<S: ShareableMiddleware + Send + Share>(s: S) -> Shared {
        Shared {
            middleware: Arc::new(box s as Box<ShareableMiddleware + Send + Share>)
        }
    }
}

// Needed to hack name resolution in our Clone impl
fn clone<T: Clone>(t: &T) -> T { t.clone() }

impl Clone for Shared {
    fn clone(&self) -> Shared {
        Shared {
            middleware: clone(&self.middleware)
        }
    }
}

impl Middleware for Shared {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        self.middleware.shared_enter(req, res, alloy)
    }

    fn exit(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        self.middleware.shared_exit(req, res, alloy)
    }
}

<commit_msg>(cleanup) Remove unnecessary 'workaround'<commit_after>use iron::{Middleware, Request, Response, Alloy};
use iron::middleware::Status;
use std::sync::Arc;

/// `Middleware` implementing this trait can be linked using `Shared` so that
/// they are not cloned for each request. This can vastly improve performance
/// for immutable middleware that are not modified while handling requests.
pub trait ShareableMiddleware {
    /// `shared_enter` is an immutable version of `enter` from the `Middleware`
    /// trait - it receives an & reference to self rather than an &mut
    /// reference.
    fn shared_enter(&self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status;

    /// `shared_exit` is an immutable version of `exit` from the `Middleware`
    /// trait - it receives an & reference to self rather than an &mut
    /// reference.
    fn shared_exit(&self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status;
}

/// `Shared` is used to wrap `ShareableMiddleware` into `Middleware` so they
/// can be linked onto a `Chain` while still avoiding unnecessary copies.
pub struct Shared {
    /// The wrapped `ShareableMiddleware`
    pub middleware: Arc<Box<ShareableMiddleware + Send + Share>>
}

impl Shared {
    /// Creates a new instance of `Shared` containing the provided
    /// `ShareableMiddleware` and allowing it to be used as `Middleware`.
    pub fn new<S: ShareableMiddleware + Send + Share>(s: S) -> Shared {
        Shared {
            middleware: Arc::new(box s as Box<ShareableMiddleware + Send + Share>)
        }
    }
}

impl Clone for Shared {
    fn clone(&self) -> Shared {
        Shared {
            middleware: self.middleware.clone()
        }
    }
}

impl Middleware for Shared {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        self.middleware.shared_enter(req, res, alloy)
    }

    fn exit(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        self.middleware.shared_exit(req, res, alloy)
    }
}

<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::c_void;

use gobject_ffi::{self, GCallback};
use source::CallbackGuard;
use translate::ToGlibPtr;

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> u64 {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty()) as u64;
    assert!(handle > 0);
    handle
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<commit_msg>Add stop_emission<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint};

use gobject_ffi::{self, GCallback};
use glib_ffi::GQuark;
use source::CallbackGuard;
use translate::ToGlibPtr;

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> u64 {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty()) as u64;
    assert!(handle > 0);
    handle
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<|endoftext|>


<commit_before>extern crate time;
use std::ops::Deref;

use ::expr::{Expr, Type, Kint, Kfloat, Result, Error as E};
use ::env::{Env};
use ::util::*;
use ::eval::funcall;

// since rust's macro cannot treat binop, work around macro is needed.
macro_rules! expr {
    ($e:expr) => {
        $e
    }
}

macro_rules! def_arith_op {
    ($name: ident, $op: tt, $init: expr) => {
        pub fn $name(mut env: &mut Env, args: &Expr) -> Result<Expr> {
            let (init, args) = match args {
                &Expr::Cons(ref hd, ref tl) => match tl.deref() {
                    tl @ &Expr::Cons(_, _) => (hd.deref().clone(), tl),
                    _ => ($init, args)
                },
                args => ($init, args)
            };
            f_foldl(env, &|_, x, y| match (x, y) {
                (&Expr::Int(x), &Expr::Int(y)) => Ok(Expr::Int(expr!(x $op y))),
                (&Expr::Float(x), &Expr::Int(y)) => Ok(Expr::Float(expr!(x $op (y as Kfloat)))),
                (&Expr::Int(x), &Expr::Float(y)) => Ok(Expr::Float(expr!((x as Kfloat) $op y))),
                (&Expr::Float(x), &Expr::Float(y)) => Ok(Expr::Float(expr!(x $op y))),
                (&Expr::Int(_), y) => Err(E::Type(Type::Int, y.clone())),
                (x, _) => Err(E::Type(Type::Int, x.clone())),

            }, &init, args)

        }
    }
}

def_arith_op!(k_add, +, Expr::Int(0));
def_arith_op!(k_sub, -, Expr::Int(0));
def_arith_op!(k_mul, *, Expr::Int(1));
def_arith_op!(k_div, /, Expr::Int(1));

pub fn k_concat(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let res = f_foldl(env, &|_, acc, x| match (acc, x) {
        (&Expr::Str(ref acc), &Expr::Str(ref x)) => Ok(Expr::Str(format!("{}{}",acc, x))),
        (_, y) => Err(E::Type(Type::Str, y.clone()))
    }
                      , &Expr::Str("".to_string()), &args);
    Ok(try!(res).clone())

}

pub fn k_funcall(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref f, ref args) => match f.deref() {
            &Expr::Proc(ref f) => funcall(env, f , args.deref()),
            f => Err(E::NotFunction(f.clone()))
        },
        args => Err(E::Form(args.clone()))
    }
}

pub fn k_cons(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (car, Any) (cdr, Any));
    Ok(kcons(car.clone(), cdr.clone()))
}

pub fn k_car(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((car, _), Cons));
    Ok(car.clone())
}

pub fn k_cdr(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((_, cdr), Cons));
    Ok(cdr.clone())

}

pub fn k_list(_: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(args.clone())
}

pub fn k_equal_p(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (x, Any) (y, Any));
    if x == y {
        // TODO: return `t`
        Ok(Expr::Int(1))
    } else {
        Ok(Expr::Nil)
    }

}

pub fn k_string_to_number(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str));
    match s.parse() {
        // TODO: handle float case
        Ok(i) => Ok(Expr::Int(i)),
        Err(_) => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn k_current_time_string(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args);
    let now = time::now();
    Ok(Expr::Str(format!("{}", now.ctime())))
}

pub fn k_substring(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str) &optional (start, Int) (end, Int));
    let len = s.len();
    let ilen = len as Kint;
    let start = start.unwrap_or(0);
    let end = end.unwrap_or(ilen);
    if 0 <= start && start <= end && end < ilen {
        let start = start as usize;
        let end = end as usize;
        Ok(Expr::Str((&s[start..end]).to_string()))
    } else {
        Err(E::InvalidArgument(args.clone()))
    }
}

pub fn init(mut env: &mut Env) -> Result<()>{
    env.fregister("+",       kprim("k_add", k_add));
    env.fregister("-",       kprim("k_sub", k_sub));
    env.fregister("/",       kprim("k_div", k_div));
    env.fregister("*",       kprim("k_mul", k_mul));
    env.fregister("concat",  kprim("k_concat", k_concat));
    env.fregister("funcall", kprim("k_funcall", k_funcall));
    env.fregister("cons",    kprim("k_cons", k_cons));
    env.fregister("car",     kprim("k_car", k_car));
    env.fregister("cdr",     kprim("k_cdr", k_cdr));
    env.fregister("list",    kprim("k_list",k_list));
    env.fregister("equal?",  kprim("k_equal_p", k_equal_p));
    env.fregister("string-to-number", kprim("k_string_to_number", k_string_to_number));
    env.fregister("substring", kprim("k_substring", k_substring));
    env.fregister("current-time-string", kprim("k_current_time_string", k_current_time_string));
    Ok(())
}

<commit_msg>enhance time related functions<commit_after>extern crate time;
use std::ops::Deref;

use ::expr::{Expr, Type, Kint, Kfloat, Result, Error as E};
use ::env::{Env};
use ::util::*;
use ::eval::funcall;

// since rust's macro cannot treat binop, work around macro is needed.
macro_rules! expr {
    ($e:expr) => {
        $e
    }
}

macro_rules! def_arith_op {
    ($name: ident, $op: tt, $init: expr) => {
        pub fn $name(mut env: &mut Env, args: &Expr) -> Result<Expr> {
            let (init, args) = match args {
                &Expr::Cons(ref hd, ref tl) => match tl.deref() {
                    tl @ &Expr::Cons(_, _) => (hd.deref().clone(), tl),
                    _ => ($init, args)
                },
                args => ($init, args)
            };
            f_foldl(env, &|_, x, y| match (x, y) {
                (&Expr::Int(x), &Expr::Int(y)) => Ok(Expr::Int(expr!(x $op y))),
                (&Expr::Float(x), &Expr::Int(y)) => Ok(Expr::Float(expr!(x $op (y as Kfloat)))),
                (&Expr::Int(x), &Expr::Float(y)) => Ok(Expr::Float(expr!((x as Kfloat) $op y))),
                (&Expr::Float(x), &Expr::Float(y)) => Ok(Expr::Float(expr!(x $op y))),
                (&Expr::Int(_), y) => Err(E::Type(Type::Int, y.clone())),
                (x, _) => Err(E::Type(Type::Int, x.clone())),

            }, &init, args)

        }
    }
}

def_arith_op!(k_add, +, Expr::Int(0));
def_arith_op!(k_sub, -, Expr::Int(0));
def_arith_op!(k_mul, *, Expr::Int(1));
def_arith_op!(k_div, /, Expr::Int(1));

pub fn k_concat(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let res = f_foldl(env, &|_, acc, x| match (acc, x) {
        (&Expr::Str(ref acc), &Expr::Str(ref x)) => Ok(Expr::Str(format!("{}{}",acc, x))),
        (_, y) => Err(E::Type(Type::Str, y.clone()))
    }
                      , &Expr::Str("".to_string()), &args);
    Ok(try!(res).clone())

}

pub fn k_funcall(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref f, ref args) => match f.deref() {
            &Expr::Proc(ref f) => funcall(env, f , args.deref()),
            f => Err(E::NotFunction(f.clone()))
        },
        args => Err(E::Form(args.clone()))
    }
}

pub fn k_cons(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (car, Any) (cdr, Any));
    Ok(kcons(car.clone(), cdr.clone()))
}

pub fn k_car(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((car, _), Cons));
    Ok(car.clone())
}

pub fn k_cdr(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((_, cdr), Cons));
    Ok(cdr.clone())

}

pub fn k_list(_: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(args.clone())
}

pub fn k_equal_p(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (x, Any) (y, Any));
    if x == y {
        // TODO: return `t`
        Ok(Expr::Int(1))
    } else {
        Ok(Expr::Nil)
    }

}

pub fn k_string_to_number(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str));
    match s.parse() {
        // TODO: handle float case
        Ok(i) => Ok(Expr::Int(i)),
        Err(_) => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn k_substring(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str) &optional (start, Int) (end, Int));
    let len = s.len();
    let ilen = len as Kint;
    let start = start.unwrap_or(0);
    let end = end.unwrap_or(ilen);
    if 0 <= start && start <= end && end < ilen {
        let start = start as usize;
        let end = end as usize;
        Ok(Expr::Str((&s[start..end]).to_string()))
    } else {
        Err(E::InvalidArgument(args.clone()))
    }
}

pub fn k_current_time(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args);
    let nbits = 16;
    let time::Timespec{sec, nsec} = time::get_time();
    let hi  = sec >> nbits;
    let lo = sec & ((1 << nbits) - 1);
    Ok(klist!(hi as Kint, lo as Kint, nsec as Kint, 0))
}

pub fn k_current_time_string(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, &optional (specified_time, Any) (_, Any));
    let nbits = 16;
    let now = match specified_time {
        None => time::now(),
        Some(t) => {
            get_args!(t, (hi, Int) (lo, Int) (nsec, Int) (_, Int));
            let hi = hi as i64;
            let lo = lo as i64;
            let sec = (hi <<nbits) + lo;
            time::at(time::Timespec{sec: sec, nsec: nsec as i32})
        }
    };
    Ok(Expr::Str(format!("{}", now.ctime())))
}

pub fn init(mut env: &mut Env) -> Result<()>{
    env.fregister("+",       kprim("k_add", k_add));
    env.fregister("-",       kprim("k_sub", k_sub));
    env.fregister("/",       kprim("k_div", k_div));
    env.fregister("*",       kprim("k_mul", k_mul));
    env.fregister("concat",  kprim("k_concat", k_concat));
    env.fregister("funcall", kprim("k_funcall", k_funcall));
    env.fregister("cons",    kprim("k_cons", k_cons));
    env.fregister("car",     kprim("k_car", k_car));
    env.fregister("cdr",     kprim("k_cdr", k_cdr));
    env.fregister("list",    kprim("k_list",k_list));
    env.fregister("equal?",  kprim("k_equal_p", k_equal_p));
    env.fregister("string-to-number", kprim("k_string_to_number", k_string_to_number));
    env.fregister("substring", kprim("k_substring", k_substring));
    env.fregister("current-time-string", kprim("k_current_time_string", k_current_time_string));
    env.fregister("current-time", kprim("k_current_time", k_current_time));
    Ok(())
}

<|endoftext|>