Skip to content

Commit 45155d8

Browse files
committed
Remove compilation warning with InstanceHandle_t (#262)
* Refs #23753. Take into account dependencies for rebuild Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Fix warning Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Remove swig warnings Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Add unit tests Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Apply suggestions Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> --------- Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> (cherry picked from commit 6ee4ca5)
1 parent 3685455 commit 45155d8

File tree

5 files changed

+398
-40
lines changed

5 files changed

+398
-40
lines changed

fastdds_python/src/swig/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set(${PROJECT_NAME}_MODULE
2727
set(${PROJECT_NAME}_FILES
2828
${${PROJECT_NAME}_MODULE}.i
2929
)
30+
set_property(SOURCE ${${PROJECT_NAME}_FILE} PROPERTY USE_SWIG_DEPENDENCIES TRUE)
3031

3132
SET_SOURCE_FILES_PROPERTIES(
3233
${${PROJECT_NAME}_FILES}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
%{
16+
#include <fastdds/dds/core/Time_t.hpp>
17+
%}
18+
19+
// Also ignore the insertion/exraction operator of the remaining Time_t,
20+
// as it makes no sense on the target language
21+
%ignore eprosima::fastdds::dds::operator<<(std::ostream&, const Time_t&);
22+
%ignore eprosima::fastdds::dds::operator>>(std::istream&, Time_t&);
23+
24+
// Ignore the global comparison and arithmetic operators
25+
// and make them class-internal
26+
%ignore eprosima::fastdds::dds::operator==(const Time_t&, const Time_t&);
27+
%ignore eprosima::fastdds::dds::operator!=(const Time_t&, const Time_t&);
28+
%ignore eprosima::fastdds::dds::operator<(const Time_t&, const Time_t&);
29+
%ignore eprosima::fastdds::dds::operator<=(const Time_t&, const Time_t&);
30+
%ignore eprosima::fastdds::dds::operator>(const Time_t&, const Time_t&);
31+
%ignore eprosima::fastdds::dds::operator>=(const Time_t&, const Time_t&);
32+
%ignore eprosima::fastdds::dds::operator+(const Time_t&, const Time_t&);
33+
%ignore eprosima::fastdds::dds::operator-(const Time_t&, const Time_t&);
34+
35+
%ignore eprosima::fastdds::dds::Time_t::is_infinite(const Time_t&);
36+
37+
// Declare the comparison operators as internal to the class
38+
%extend eprosima::fastdds::dds::Time_t {
39+
bool operator==(const eprosima::fastdds::dds::Time_t& other) const
40+
{
41+
return *$self == other;
42+
}
43+
44+
bool operator!=(const eprosima::fastdds::dds::Time_t& other) const
45+
{
46+
return *$self != other;
47+
}
48+
49+
bool operator<(const eprosima::fastdds::dds::Time_t& other) const
50+
{
51+
return *$self < other;
52+
}
53+
54+
bool operator>(const eprosima::fastdds::dds::Time_t& other) const
55+
{
56+
return *$self > other;
57+
}
58+
59+
bool operator<=(const eprosima::fastdds::dds::Time_t& other) const
60+
{
61+
return *$self <= other;
62+
}
63+
64+
bool operator>=(const eprosima::fastdds::dds::Time_t& other) const
65+
{
66+
return *$self >= other;
67+
}
68+
69+
eprosima::fastdds::dds::Time_t operator+ (const eprosima::fastdds::dds::Time_t& other) const
70+
{
71+
return *$self + other;
72+
}
73+
74+
eprosima::fastdds::dds::Time_t operator- (const eprosima::fastdds::dds::Time_t& other) const
75+
{
76+
return *$self - other;
77+
}
78+
}
79+
80+
%include <fastdds/dds/core/Time_t.hpp>
81+
82+
namespace eprosima {
83+
namespace fastdds {
84+
namespace dds {
85+
86+
struct Duration_t : public Time_t
87+
{
88+
Duration_t();
89+
90+
Duration_t(
91+
int32_t sec,
92+
uint32_t nsec);
93+
};
94+
95+
} // namespace dds
96+
} // namespace fastdds
97+
} // namespace eprosima

fastdds_python/src/swig/fastdds/rtps/common/InstanceHandle.i

Lines changed: 149 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// limitations under the License.
1414

1515
%{
16+
#include <stdexcept>
17+
#include <vector>
18+
1619
#include "fastdds/rtps/common/InstanceHandle.h"
1720

1821
// Define a hash method in global scope for InstanceHandle_t types
@@ -26,60 +29,119 @@ long hash(const eprosima::fastrtps::rtps::InstanceHandle_t& handle)
2629
}
2730
return ret;
2831
}
29-
3032
%}
3133

3234
// SWIG does not support type conversion operators correctly unless converted to a normal method
3335
%rename(get_guid) eprosima::fastrtps::rtps::InstanceHandle_t::operator const GUID_t&;
3436

35-
%ignore eprosima::fastrtps::rtps::InstanceHandleValue_t::operator [] const;
36-
%ignore eprosima::fastrtps::rtps::operator <<(std::ostream&, const InstanceHandle_t&);
37-
%ignore eprosima::fastrtps::rtps::operator >>(std::istream&, InstanceHandle_t&);
38-
%rename(read_pointer_cast) eprosima::fastrtps::rtps::InstanceHandleValue_t::operator const octet* () const;
39-
%rename(write_pointer_cast) eprosima::fastrtps::rtps::InstanceHandleValue_t::operator octet* ();
40-
41-
%typemap(in) eprosima::fastrtps::rtps::InstanceHandleValue_t*(eprosima::fastrtps::rtps::InstanceHandleValue_t temp)
42-
{
43-
if (PyTuple_Check($input))
44-
{
45-
eprosima::fastrtps::rtps::octet* buf = temp;
46-
if (!PyArg_ParseTuple($input, "BBBBBBBBBBBBBBBB",
47-
buf, buf+1, buf+2, buf+3, buf+4, buf+5, buf+6, buf+7, buf+8,
48-
buf+9, buf+10, buf+11, buf+12, buf+13, buf+14, buf+15))
37+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator [] const;
38+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator [];
39+
%ignore eprosima::fastdds::rtps::operator <<(std::ostream&, const InstanceHandle_t&);
40+
%ignore eprosima::fastdds::rtps::operator >>(std::istream&, InstanceHandle_t&);
41+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator const octet* () const;
42+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator octet* ();
43+
44+
%extend eprosima::fastdds::rtps::InstanceHandleValue_t {
45+
46+
// Constructor from a sequence of 16 bytes (tuple/list/bytes/bytearray)
47+
InstanceHandleValue_t(PyObject* seq) {
48+
eprosima::fastdds::rtps::InstanceHandleValue_t* self = new eprosima::fastdds::rtps::InstanceHandleValue_t();
49+
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
50+
51+
// Fast-path: bytes
52+
if (PyBytes_Check(seq)) {
53+
if (PyBytes_GET_SIZE(seq) == 16)
54+
{
55+
const char* b = PyBytes_AS_STRING(seq);
56+
for (int i = 0; i < 16; ++i) (*self)[i] = (uint8_t)(unsigned char)b[i];
57+
}
58+
else
59+
{
60+
delete self;
61+
self = nullptr;
62+
PyErr_SetString(PyExc_ValueError, "Expected 16 bytes");
63+
}
64+
}
65+
// Fast-path: bytearray
66+
else if (PyByteArray_Check(seq))
4967
{
50-
PyErr_SetString(PyExc_TypeError, "tuple must have 16 elements");
51-
SWIG_fail;
68+
if (PyByteArray_GET_SIZE(seq) == 16)
69+
{
70+
const char* b = PyByteArray_AS_STRING(seq);
71+
for (int i = 0; i < 16; ++i) (*self)[i] = (uint8_t)(unsigned char)b[i];
72+
}
73+
else
74+
{
75+
delete self;
76+
self = nullptr;
77+
PyErr_SetString(PyExc_ValueError, "Expected 16 bytes");
78+
}
5279
}
53-
$1 = &temp;
54-
}
55-
else
56-
{
57-
PyErr_SetString(PyExc_TypeError, "expected a tuple.");
58-
SWIG_fail;
80+
else
81+
{
82+
// Generic fallback: iterable from 16 ints 0..255
83+
PyObject* it = PyObject_GetIter(seq);
84+
size_t count {0};
85+
if (it)
86+
{
87+
PyObject* item {nullptr};
88+
while ((item = PyIter_Next(it)) && count < 16)
89+
{
90+
long val = PyLong_AsLong(item);
91+
Py_DECREF(item);
92+
if (val == -1 && PyErr_Occurred())
93+
{
94+
delete self;
95+
self = nullptr;
96+
PyErr_SetString(PyExc_TypeError, "Sequence must contain integers");
97+
break;
98+
}
99+
else if (val < 0 || val > 255)
100+
{
101+
delete self;
102+
self = nullptr;
103+
PyErr_SetString(PyExc_ValueError, "Each value must be in 0..255");
104+
break;
105+
}
106+
107+
(*self)[count] = static_cast<uint8_t>(val);
108+
++count;
109+
}
110+
Py_DECREF(it);
111+
if ((nullptr != item || count != 16) && nullptr != self)
112+
{
113+
delete self;
114+
self = nullptr;
115+
PyErr_SetString(PyExc_ValueError, "Expected 16 elements");
116+
}
117+
}
118+
else
119+
{
120+
delete self;
121+
self = nullptr;
122+
PyErr_SetString(PyExc_TypeError, "Expected a sequence of 16 integers (0..255) or 16-byte object");
123+
}
124+
}
125+
126+
SWIG_PYTHON_THREAD_END_BLOCK;
127+
128+
return self;
59129
}
60-
}
61130

62-
%typemap(out) eprosima::fastrtps::rtps::InstanceHandleValue_t*
63-
{
64-
constexpr size_t ih_size = std::tuple_size<eprosima::fastrtps::rtps::KeyHash_t>::value;
65-
PyObject* python_tuple = PyTuple_New(ih_size);
131+
size_t __len__() const { return 16; }
66132

67-
if (python_tuple)
68-
{
69-
for(size_t count = 0; count < ih_size; ++count)
70-
{
71-
PyTuple_SetItem(python_tuple, count, PyInt_FromLong((*$1)[count]));
72-
}
133+
uint8_t __getitem__(size_t i) const {
134+
if (i >= 16) throw std::out_of_range("index out of range");
135+
return $self->operator[](i);
73136
}
74137

75-
$result = python_tuple;
138+
void __setitem__(size_t i, uint8_t v) {
139+
if (i >= 16) throw std::out_of_range("index out of range");
140+
$self->operator[](i) = v;
141+
}
76142
}
77143

78-
// Template for std::vector<InstanceHandle_t>
79-
%template(InstanceHandleVector) std::vector<eprosima::fastrtps::rtps::InstanceHandle_t>;
80-
%typemap(doctype) std::vector<eprosima::fastrtps::rtps::InstanceHandle_t>"InstanceHandleVector";
81-
82-
%include "fastdds/rtps/common/InstanceHandle.h"
144+
%ignore eprosima::fastdds::rtps::InstanceHandle_t::value;
83145

84146
// Declare the comparison operators as internal to the class
85147
%extend eprosima::fastrtps::rtps::InstanceHandle_t {
@@ -106,4 +168,51 @@ long hash(const eprosima::fastrtps::rtps::InstanceHandle_t& handle)
106168
{
107169
return hash(*$self);
108170
}
171+
172+
// Setter from sequence (tuple/list/bytes/bytearray)
173+
void from_sequence(PyObject* seq) {
174+
// Reuse the constructor to validate and copy
175+
eprosima::fastdds::rtps::InstanceHandleValue_t* tmp = new_eprosima_fastdds_rtps_InstanceHandleValue_t(seq);
176+
if (nullptr != tmp)
177+
{
178+
for (int i = 0; i < 16; ++i) $self->value[i] = (*tmp)[i];
179+
delete tmp; // avoid memory leak
180+
}
181+
}
182+
183+
// Getter: return a tuple of 16 ints (0..255)
184+
PyObject* to_sequence() const {
185+
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
186+
187+
PyObject* python_tuple = PyTuple_New(16);
188+
189+
if (python_tuple)
190+
{
191+
for(size_t count = 0; count < 16; ++count)
192+
{
193+
PyTuple_SetItem(python_tuple, count, PyInt_FromLong($self->value[count]));
194+
}
195+
}
196+
197+
SWIG_PYTHON_THREAD_END_BLOCK;
198+
199+
return python_tuple;
200+
}
109201
}
202+
203+
// Template for std::vector<InstanceHandle_t>
204+
%template(InstanceHandleVector) std::vector<eprosima::fastdds::rtps::InstanceHandle_t>;
205+
%typemap(doctype) std::vector<eprosima::fastdds::rtps::InstanceHandle_t>"InstanceHandleVector";
206+
207+
%include "fastdds/rtps/common/InstanceHandle.h"
208+
209+
%pythoncode %{
210+
def _ihv_get_value(self):
211+
return self.to_sequence()
212+
213+
def _ihv_set_value(self, seq):
214+
self.from_sequence(seq)
215+
216+
InstanceHandle_t.value = property(_ihv_get_value, _ihv_set_value,
217+
doc="16-byte value as list/tuple/bytes/bytearray")
218+
%}

fastdds_python/test/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ if (${fastcdr_VERSION_MAJOR} EQUAL 1)
2020
set(fastcdr_version_argument "v1")
2121
endif()
2222

23+
# Unit tests
24+
add_test(NAME unit_tests
25+
COMMAND
26+
${Python3_EXECUTABLE}
27+
-m pytest
28+
-vrP
29+
WORKING_DIRECTORY
30+
${CMAKE_CURRENT_SOURCE_DIR}/unittest
31+
)
2332

33+
# DDS Api tests
2434
add_test(NAME api_tests
2535
COMMAND
2636
${Python3_EXECUTABLE}

0 commit comments

Comments
 (0)