Skip to content

Commit f051d17

Browse files
Generate swig code for interfaces (#477)
* Refs #23079. Add interfaces code to TypesSwigInterface.stg Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Swig code for operation return types. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Improvements on RpcClientReader. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Avoid duplicates of code generated for template classes. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Generate code for input feeds. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Generate code to catch exceptions. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Director feature for ServerImplementation classes. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Avoid Server code for nested interfaces. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Server code for feeds. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Refactor output arguments. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Enable thread support for directors and release lock in server run(). Signed-off-by: Miguel Company <[email protected]> * Refs #23232. Avoid generating detail namespace for interfaces without output arguments. Signed-off-by: Miguel Company <[email protected]> * Windows compilation Fix Signed-off-by: Mario Dominguez <[email protected]> * MacOs warning Fix Signed-off-by: Mario Dominguez <[email protected]> * Refs #23079. Add copyright header to SwigCMake template. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Apply review. Signed-off-by: Miguel Company <[email protected]> * Refs #23079. Directors only necessary when there are interfaces. Signed-off-by: Miguel Company <[email protected]> --------- Signed-off-by: Miguel Company <[email protected]> Signed-off-by: Mario Dominguez <[email protected]> Co-authored-by: Mario Dominguez <[email protected]>
1 parent aeac2ad commit f051d17

File tree

8 files changed

+325
-30
lines changed

8 files changed

+325
-30
lines changed

src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeader.stg

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,12 @@ private:
190190

191191
interface(ctx, parent, interface, export_list) ::= <<
192192

193+
$if(interface.withOutputParameters)$
193194
namespace detail {
194195

195196
$interface.operations : { op | $if(op.outputparam)$$operation_out_struct_fwd_decl(interface, op)$$endif$}$
196-
}
197+
} // namespace detail
198+
$endif$
197199

198200
/*!
199201
* @brief This class represents the interface $interface.name$ defined by the user in the IDL file.
@@ -207,10 +209,12 @@ public:
207209
$export_list$
208210
};
209211

212+
$if(interface.withOutputParameters)$
210213
namespace detail {
211214

212215
$interface.operations : { op | $if(op.outputparam)$$operation_out_struct(interface, op)$$"\n"$$endif$}$
213-
}
216+
} // namespace detail
217+
$endif$
214218
>>
215219

216220
operation(ctx, parent, operation, param_list, operation_type) ::= <<

src/main/java/com/eprosima/fastcdr/idl/templates/TypesSwigInterface.stg

Lines changed: 201 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,20 @@
1515
group TypesSwigInterface;
1616

1717
import "com/eprosima/fastdds/idl/templates/eprosima.stg"
18+
import "FastCdrCommon.stg"
1819

1920
main(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) ::= <<
241379
enum_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

Comments
 (0)