1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
/*
* Copyright (c) 2014 Christian Authmann
*/
#pragma once
#include "common/typeid.h"
#include "common/binarystream.h"
#include "common/constants.h"
#include "rinside_callbacks.h"
#include <stdexcept>
#include <map>
#include <functional>
class CppFunctionForRInsideServer;
class RInsideServer {
public:
RInsideServer(BinaryStream &stream, RInside &R, RInsideCallbacks &Rcallbacks);
~RInsideServer();
void run();
private:
SEXP sexp_from_stream();
void sexp_to_stream(SEXP, int32_t type, bool include_reply = false);
BinaryStream stream;
RInside &R;
RInsideCallbacks &Rcallbacks;
bool can_send_reply;
void sendReply(char reply) { if (!can_send_reply) throw std::runtime_error("Cannot send a reply at this time, exiting"); can_send_reply = false; stream.write(reply); }
void allowSendReply() { if (can_send_reply) throw std::runtime_error("allowSendReply() called twice, exiting"); can_send_reply = true; }
static std::map<int32_t, std::function<SEXP(BinaryStream &)> > registry_sexp_from_stream;
static std::map<int32_t, std::function<void(RInsideServer &, SEXP, bool)> > registry_sexp_to_stream;
public:
static void registerDefaultTypes();
template <typename T>
static void registerType() {
int32_t type = TYPEID<T>();
if (registry_sexp_from_stream.count(type) > 0 || registry_sexp_to_stream.count(type) > 0)
throw std::runtime_error("registerType(): type already registered");
registry_sexp_from_stream[type] = [] (BinaryStream &stream) -> SEXP {
T value = stream.read<T>();
return Rcpp::wrap<T>(value);
};
registry_sexp_to_stream[type] = [type] (RInsideServer &server, SEXP sexp, bool include_reply) -> void {
T value = Rcpp::as<T>(sexp);
/*
* The reply should be sent after type conversion. If type conversion throws an exception,
* the server cannot reply with REPLY_ERROR after another reply has been sent.
*/
if (include_reply)
server.sendReply(RIS_REPLY_VALUE);
server.stream.write(type);
server.stream.write(value);
};
}
friend class CppFunctionForRInsideServer;
};
|