1515group TypesSwigInterface;
1616
1717import "com/eprosima/fastdds/idl/templates/eprosima.stg"
18+ import "FastCdrCommon.stg"
1819
1920main(ctx, definitions) ::= <<
2021$fileHeader(ctx=ctx, file=[ctx.filename, ".i"], description=["This header file contains the SWIG interface of the described types in the IDL file."])$
2122
22- %module(moduleimport="if __import__('os').name == 'nt': import win32api; win32api.LoadLibrary('$ctx.filename$.dll')\nif __package__ or '.' in __name__:\n from . import _$ctx.filename$Wrapper\nelse:\n import _$ctx.filename$Wrapper") $ctx.filename$
23+ %module($if(ctx.thereIsInterface)$threads="1",directors="1",$endif$moduleimport="if __import__('os').name == 'nt': import win32api; win32api.LoadLibrary('$ctx.filename$.dll')\nif __package__ or '.' in __name__:\n from . import _$ctx.filename$Wrapper\nelse:\n import _$ctx.filename$Wrapper") $ctx.filename$
24+
25+ $if(ctx.thereIsInterface)$
26+ // We have enabled threads because the RPC server directors will call the target language environment
27+ // from the C++ server threads, but we don't want the calls from the target language to release their
28+ // locks (e.g. Python GIL) when calling the C++ methods.
29+ // See a very nice explanation at https://github.com/swig/swig/issues/927#issuecomment-289279243
30+ %feature("nothreadallow");
31+ $endif$
2332
2433// If using windows in debug, it would try to use python_d, which would not be found.
2534%begin %{
@@ -30,9 +39,16 @@ $fileHeader(ctx=ctx, file=[ctx.filename, ".i"], description=["This header file c
3039%}
3140
3241// SWIG helper modules
42+ $if(ctx.thereIsInterface)$
43+ %include "exception.i"
44+ $endif$
3345%include "stdint.i"
3446%include "std_array.i"
3547%include "std_map.i"
48+ $if(ctx.thereIsInterface)$
49+ %include "std_pair.i"
50+ %include "std_shared_ptr.i"
51+ $endif$
3652%include "std_string.i"
3753%include "std_vector.i"
3854%include "typemaps.i"
@@ -47,6 +63,11 @@ $ctx.directIncludeDependencies : {include | %include "$include$.i"}; separator="
4763
4864%{
4965#include "$ctx.filename$.hpp"
66+ $if(ctx.thereIsInterface)$
67+ #include "$ctx.filename$Client.hpp"
68+ #include "$ctx.filename$Server.hpp"
69+ #include "$ctx.filename$ServerImpl.hpp"
70+ $endif$
5071
5172#include <fastdds/dds/core/LoanableSequence.hpp>
5273%}
@@ -62,6 +83,118 @@ $endif$
6283%import(module="fastdds") "fastdds/dds/core/LoanableTypedCollection.hpp"
6384%import(module="fastdds") "fastdds/dds/core/LoanableSequence.hpp"
6485
86+ $if(ctx.thereIsInterface)$
87+ %import(module="fastdds") "fastdds/dds/rpc/exceptions/RpcException.hpp"
88+ %import(module="fastdds") "fastdds/dds/rpc/exceptions/RpcOperationError.hpp"
89+
90+ %exception {
91+ try
92+ {
93+ \$action
94+ }
95+ catch (const eprosima::fastdds::dds::rpc::RpcException& ex)
96+ {
97+ SWIG_exception(SWIG_RuntimeError, ex.what());
98+ }
99+ catch (const std::exception& ex)
100+ {
101+ SWIG_exception(SWIG_RuntimeError, ex.what());
102+ }
103+ catch (...)
104+ {
105+ SWIG_exception(SWIG_RuntimeError,"Unknown exception");
106+ }
107+ }
108+
109+ $if(ctx.thereIsOutputFeed)$
110+ %import(module="fastdds") "fastdds/dds/rpc/interfaces/RpcServerWriter.hpp"
111+ %ignore eprosima::fastdds::dds::rpc::RpcClientReader::read(T&);
112+ %ignore eprosima::fastdds::dds::rpc::RpcClientReader::read(T&,eprosima::fastdds::dds::Duration_t&);
113+ %import(module="fastdds") "fastdds/dds/rpc/interfaces/RpcClientReader.hpp"
114+ %extend eprosima::fastdds::dds::rpc::RpcClientReader {
115+ std::pair<bool, T> read(
116+ const eprosima::fastdds::dds::Duration_t& timeout = eprosima::fastdds::dds::c_TimeInfinite)
117+ {
118+ std::pair<bool, T> ret_val{};
119+ if (eprosima::fastdds::dds::c_TimeInfinite == timeout)
120+ {
121+ ret_val.first = self->read(ret_val.second);
122+ }
123+ else
124+ {
125+ ret_val.first = self->read(ret_val.second, timeout);
126+ }
127+ return ret_val;
128+ }
129+ }
130+
131+ $ctx.outputFeedTypes : {feed_type | $output_feed(feed_type)$}; separator="\n\n"$
132+ $endif$
133+
134+ $if(ctx.thereIsNonFeedOperation)$
135+ // Code for std::future taken from https://github.com/swig/swig/issues/1828#issuecomment-648449092
136+ namespace eprosima::fastdds::dds::rpc
137+ {
138+ template <class R>
139+ class RpcFuture {
140+ public:
141+ RpcFuture() noexcept;
142+ RpcFuture(RpcFuture &&) noexcept;
143+ RpcFuture(const RpcFuture& rhs) = delete;
144+ ~RpcFuture();
145+ RpcFuture& operator=(const RpcFuture& rhs) = delete;
146+ RpcFuture& operator=(RpcFuture&&) noexcept;
147+
148+ // retrieving the value
149+ R get();
150+
151+ // functions to check state
152+ bool valid() const noexcept;
153+ void wait() const;
154+
155+ /*
156+ template <class Rep, class Period>
157+ future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
158+ template <class Clock, class Duration>
159+ future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
160+ */
161+ };
162+
163+ }
164+
165+ $ctx.outputNonFeedTypes : {non_feed_type | $output_non_feed(non_feed_type)$}; separator="\n\n"$
166+ $endif$
167+
168+ $if(ctx.thereIsInputFeed)$
169+ %import(module="fastdds") "fastdds/dds/rpc/interfaces/RpcClientWriter.hpp"
170+ %import(module="fastdds") "fastdds/dds/rpc/interfaces/RpcStatusCode.hpp"
171+
172+ %ignore eprosima::fastdds::dds::rpc::RpcServerReader::read(T&);
173+ %ignore eprosima::fastdds::dds::rpc::RpcServerReader::read(T&,eprosima::fastdds::dds::Duration_t&);
174+ %import(module="fastdds") "fastdds/dds/rpc/interfaces/RpcServerReader.hpp"
175+ %extend eprosima::fastdds::dds::rpc::RpcServerReader {
176+ std::pair<bool, T> read(
177+ const eprosima::fastdds::dds::Duration_t& timeout = eprosima::fastdds::dds::c_TimeInfinite)
178+ {
179+ std::pair<bool, T> ret_val{};
180+ if (eprosima::fastdds::dds::c_TimeInfinite == timeout)
181+ {
182+ ret_val.first = self->read(ret_val.second);
183+ }
184+ else
185+ {
186+ ret_val.first = self->read(ret_val.second, timeout);
187+ }
188+ return ret_val;
189+ }
190+ }
191+
192+ $ctx.inputFeedTypes : {feed_type | $input_feed(feed_type)$}; separator="\n\n"$
193+ $endif$
194+
195+ %exception;
196+ $endif$
197+
65198%define %traits_penumn(Type...)
66199 %fragment(SWIG_Traits_frag(Type),"header",
67200 fragment="StdTraits") {
@@ -78,6 +211,11 @@ $definitions; separator="\n"$
78211
79212// Include the class interfaces
80213%include "$ctx.filename$.hpp"
214+ $if(ctx.thereIsInterface)$
215+ %include "$ctx.filename$Client.hpp"
216+ %include "$ctx.filename$Server.hpp"
217+ %include "$ctx.filename$ServerImpl.hpp"
218+ $endif$
81219
82220// Include the corresponding TopicDataType
83221%include "$ctx.filename$PubSubTypes.i"
@@ -241,3 +379,65 @@ bitset_type(ctx, parent, bitset, extensions) ::= <<
241379enum_type(ctx, parent, enum) ::= <<
242380%traits_penumn(enum $enum.cppTypename$);
243381>>
382+
383+ interface(ctx, parent, interface, export_list) ::= <<
384+
385+ $export_list$
386+
387+ %shared_ptr($interface.scopedname$);
388+ $if(!interface.annotatedAsNested)$
389+ %shared_ptr($interface.scopedname$Server);
390+ %extend $interface.scopedname$Server
391+ {
392+ void run()
393+ {
394+ Py_BEGIN_ALLOW_THREADS
395+ self->run();
396+ Py_END_ALLOW_THREADS
397+ }
398+ }
399+
400+ %shared_ptr($interface.scopedname$Server_IServerImplementation);
401+ %shared_ptr($interface.scopedname$ServerImplementation);
402+ %feature("director") $interface.scopedname$ServerImplementation;
403+ $endif$
404+ >>
405+
406+ output_non_feed(type) ::= <<
407+ %shared_ptr(eprosima::fastdds::dds::rpc::RpcFuture<$type.cppTypename$>);
408+ %template($type.formatedCppTypename$_rpc_future) eprosima::fastdds::dds::rpc::RpcFuture<$type.cppTypename$>;
409+
410+ $!
411+ // Combine the typemap from shared_ptr
412+ // https://github.com/swig/swig/blob/b96b955ca15a01f0425fb26c234528530923202a/Lib/python/boost_shared_ptr.i#L41-L44
413+ // with the use of the 'optimal' attribute to avoid the need for a copy constructor, inspired by
414+ // https://github.com/swig/swig/issues/1828#issuecomment-648449092
415+ !$
416+ %typemap(out, optimal="1") eprosima::fastdds::dds::rpc::RpcFuture<$type.cppTypename$> {
417+ std::shared_ptr<\$1_ltype> *smartresult = new std::shared_ptr<\$1_ltype>(new \$1_ltype(\$1));
418+ \$result = SWIG_NewPointerObj(SWIG_as_voidptr(smartresult), \$descriptor(std::shared_ptr< eprosima::fastdds::dds::rpc::RpcFuture<$type.cppTypename$\>> *), SWIG_POINTER_OWN);
419+ }
420+ >>
421+
422+ output_feed(type) ::= <<
423+ %shared_ptr(eprosima::fastdds::dds::rpc::RpcClientReader<$type.cppTypename$>);
424+ %template($type.formatedCppTypename$_client_reader_result) std::pair<bool, $type.cppTypename$>;
425+ %template($type.formatedCppTypename$_client_reader) eprosima::fastdds::dds::rpc::RpcClientReader<$type.cppTypename$>;
426+
427+ %template($type.formatedCppTypename$_server_writer) eprosima::fastdds::dds::rpc::RpcServerWriter<$type.cppTypename$>;
428+ >>
429+
430+ input_feed(type) ::= <<
431+ %template($type.formatedCppTypename$_server_reader_result) std::pair<bool, $type.cppTypename$>;
432+ %template($type.formatedCppTypename$_server_reader) eprosima::fastdds::dds::rpc::RpcServerReader<$type.cppTypename$>;
433+
434+ %shared_ptr(eprosima::fastdds::dds::rpc::RpcClientWriter<$type.cppTypename$>);
435+ %template($type.formatedCppTypename$_rpc_client_writer) eprosima::fastdds::dds::rpc::RpcClientWriter<$type.cppTypename$>;
436+ %typemap(in,numinputs=0) std::shared_ptr<eprosima::fastdds::dds::rpc::RpcClientWriter<$type.cppTypename$\>>& %{
437+ \$1 = new std::shared_ptr<eprosima::fastdds::dds::rpc::RpcClientWriter<$type.cppTypename$\>>();
438+ %}
439+ %typemap(argout) std::shared_ptr<eprosima::fastdds::dds::rpc::RpcClientWriter<$type.cppTypename$\>>& (PyObject* tmp) %{
440+ tmp = SWIG_NewPointerObj(\$1, \$1_descriptor, SWIG_POINTER_OWN);
441+ \$result = SWIG_Python_AppendOutput(\$result, tmp);
442+ %}
443+ >>
0 commit comments