File: rinsideserver.h

package info (click to toggle)
r-cran-rinside 0.2.19-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 668 kB
  • sloc: cpp: 3,310; ansic: 117; xml: 57; ruby: 34; makefile: 2
file content (69 lines) | stat: -rw-r--r-- 2,169 bytes parent folder | download | duplicates (5)
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;
};