Skip to content

Commit

Permalink
add WString support
Browse files Browse the repository at this point in the history
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
  • Loading branch information
dirk-thomas committed Apr 30, 2019
1 parent d1edcaf commit a4e7463
Show file tree
Hide file tree
Showing 19 changed files with 274 additions and 28 deletions.
12 changes: 11 additions & 1 deletion rosidl_adapter/rosidl_adapter/msg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def convert_msg_to_idl(package_dir, package_name, input_file, output_dir):
'float32': 'float',
'float64': 'double',
'string': 'string',
'wstring': 'wstring',
}


Expand All @@ -69,6 +70,8 @@ def to_idl_literal(idl_type, value):
return 'TRUE' if value else 'FALSE'
if idl_type.startswith('string'):
return string_to_idl_string_literal(value)
if idl_type.startswith('wstring'):
return string_to_idl_wstring_literal(value)
return value


Expand All @@ -79,6 +82,10 @@ def string_to_idl_string_literal(string):
return '"{0}"'.format(estr)


def string_to_idl_wstring_literal(string):
return string_to_idl_string_literal(string)


def get_include_file(base_type):
if base_type.is_primitive_type():
return None
Expand All @@ -90,7 +97,10 @@ def get_idl_type(type_):
identifier = MSG_TYPE_TO_IDL[type_]
elif type_.is_primitive_type():
identifier = MSG_TYPE_TO_IDL[type_.type]
if identifier == 'string' and type_.string_upper_bound is not None:
if (
identifier in ('string', 'wstring') and
type_.string_upper_bound is not None
):
identifier += '<{type_.string_upper_bound}>'.format_map(locals())
else:
identifier = '{type_.pkg_name}::msg::{type_.type}' \
Expand Down
17 changes: 10 additions & 7 deletions rosidl_adapter/rosidl_adapter/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
'int64',
'uint64',
'string',
# TODO reconsider wstring / u16string / u32string
'wstring',
# TODO duration and time
'duration', # for compatibility only
'time', # for compatibility only
Expand Down Expand Up @@ -157,9 +157,12 @@ def __init__(self, type_string, context_package_name=None):
self.type = type_string
self.string_upper_bound = None

elif type_string.startswith('string%s' % STRING_UPPER_BOUND_TOKEN):
elif (
type_string.startswith('string%s' % STRING_UPPER_BOUND_TOKEN) or
type_string.startswith('wstring%s' % STRING_UPPER_BOUND_TOKEN)
):
self.pkg_name = None
self.type = 'string'
self.type = type_string.split(STRING_UPPER_BOUND_TOKEN, 1)[0]
upper_bound_string = type_string[len(self.type) +
len(STRING_UPPER_BOUND_TOKEN):]

Expand Down Expand Up @@ -321,7 +324,7 @@ def __eq__(self, other):

def __str__(self):
value = self.value
if self.type == 'string':
if self.type in ('string', 'wstring'):
value = "'%s'" % value
return '%s %s=%s' % (self.type, self.name, value)

Expand Down Expand Up @@ -356,7 +359,7 @@ def __str__(self):
s = '%s %s' % (str(self.type), self.name)
if self.default_value is not None:
if self.type.is_primitive_type() and not self.type.is_array and \
self.type.type == 'string':
self.type.type in ('string', 'wstring'):
s += " '%s'" % self.default_value
else:
s += ' %s' % self.default_value
Expand Down Expand Up @@ -571,7 +574,7 @@ def parse_value_string(type_, value_string):
"array value must start with '[' and end with ']'")
elements_string = value_string[1:-1]

if type_.type == 'string':
if type_.type in ('string', 'wstring'):
# String arrays need special processing as the comma can be part of a quoted string
# and not a separator of array elements
value_strings = parse_string_array_value_string(elements_string, type_.array_size)
Expand Down Expand Up @@ -725,7 +728,7 @@ def parse_primitive_value_string(type_, value_string):

return value

if primitive_type == 'string':
if primitive_type in ('string', 'wstring'):
# remove outer quotes to allow leading / trailing spaces in the string
for quote in ['"', "'"]:
if value_string.startswith(quote) and value_string.endswith(quote):
Expand Down
21 changes: 12 additions & 9 deletions rosidl_adapter/test/test_base_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,24 @@ def test_base_type_constructor():
'uint32',
'int64',
'uint64',
'string']
'string',
'wstring']
for primitive_type in primitive_types:
base_type = BaseType(primitive_type)
assert base_type.pkg_name is None
assert base_type.type == primitive_type
assert base_type.string_upper_bound is None

base_type = BaseType('string<=23')
assert base_type.pkg_name is None
assert base_type.type == 'string'
assert base_type.string_upper_bound == 23
for string_type in ('string', 'wstring'):
base_type = BaseType('%s<=23' % string_type)
assert base_type.pkg_name is None
assert base_type.type == string_type
assert base_type.string_upper_bound == 23

with pytest.raises(TypeError):
BaseType('string<=upperbound')
with pytest.raises(TypeError):
BaseType('string<=0')
with pytest.raises(TypeError):
BaseType('%s<=upperbound' % string_type)
with pytest.raises(TypeError):
BaseType('%s<=0' % string_type)

base_type = BaseType('pkg/Msg')
assert base_type.pkg_name == 'pkg'
Expand Down Expand Up @@ -84,3 +86,4 @@ def test_base_type_methods():
assert str(BaseType('pkg/Foo')) == 'pkg/Foo'
assert str(BaseType('bool')) == 'bool'
assert str(BaseType('string<=5')) == 'string<=5'
assert str(BaseType('wstring<=5')) == 'wstring<=5'
1 change: 1 addition & 0 deletions rosidl_adapter/test/test_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ def test_constant_methods():
assert str(Constant('bool', 'FOO', '1')) == 'bool FOO=True'

assert str(Constant('string', 'FOO', 'foo')) == "string FOO='foo'"
assert str(Constant('wstring', 'FOO', 'foo')) == "wstring FOO='foo'"
70 changes: 70 additions & 0 deletions rosidl_adapter/test/test_parse_primitive_value_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,76 @@ def test_parse_primitive_value_string_string():
assert value == '"foo"'


def test_parse_primitive_value_wstring_string():
value = parse_primitive_value_string(
Type('wstring'), 'foo')
assert value == 'foo'

value = parse_primitive_value_string(
Type('wstring'), '"foo"')
assert value == 'foo'

value = parse_primitive_value_string(
Type('wstring'), "'foo'")
assert value == 'foo'

value = parse_primitive_value_string(
Type('wstring'), '"\'foo\'"')
assert value == "'foo'"

value = parse_primitive_value_string(
Type('wstring'), '"foo ')
assert value == '"foo '

value = parse_primitive_value_string(
Type('wstring<=3'), 'foo')
assert value == 'foo'

with pytest.raises(InvalidValue):
parse_primitive_value_string(
Type('wstring<=3'), 'foobar')

with pytest.raises(InvalidValue):
parse_primitive_value_string(
Type('wstring'), r"""'foo''""")

with pytest.raises(InvalidValue):
parse_primitive_value_string(
Type('wstring'), r'''"foo"bar\"baz"''') # noqa: Q001

value = parse_primitive_value_string(
Type('wstring'), '"foo')
assert value == '"foo'

value = parse_primitive_value_string(
Type('wstring'), '"foo')
assert value == '"foo'

value = parse_primitive_value_string(
Type('wstring'), "'foo")
assert value == "'foo"

value = parse_primitive_value_string(
Type('wstring'), '"foo')
assert value == '"foo'

value = parse_primitive_value_string(
Type('wstring'), "'fo'o")
assert value == "'fo'o"

value = parse_primitive_value_string(
Type('wstring'), '"fo"o')
assert value == '"fo"o'

value = parse_primitive_value_string(
Type('wstring'), r'''"'foo'"''') # noqa: Q001
assert value == "'foo'"

value = parse_primitive_value_string(
Type('wstring'), r"""'"foo"'""")
assert value == '"foo"'


def test_parse_primitive_value_string_unknown():
class CustomType(Type):

Expand Down
1 change: 1 addition & 0 deletions rosidl_generator_c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ if(BUILD_TESTING)
"msg/Uint8.msg"
"msg/Various.msg"
"msg/Wire.msg"
"msg/WStrings.msg"
"srv/AddTwoInts.srv"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ bool
rosidl_generator_c__U16String__assignn(
rosidl_generator_c__U16String * str, const uint16_t * value, size_t n);

ROSIDL_GENERATOR_C_PUBLIC
bool
rosidl_generator_c__U16String__assignn_from_char(
rosidl_generator_c__U16String * str, const char * value, size_t n);

ROSIDL_GENERATOR_C_PUBLIC
bool
rosidl_generator_c__U16String__assign(
Expand All @@ -54,6 +59,11 @@ ROSIDL_GENERATOR_C_PUBLIC
size_t
rosidl_generator_c__U16String__len(const uint16_t * value);

ROSIDL_GENERATOR_C_PUBLIC
bool
rosidl_generator_c__U16String__resize(
rosidl_generator_c__U16String * str, size_t n);

ROSIDL_GENERATOR_C_PUBLIC
bool
rosidl_generator_c__U16String__Sequence__init(
Expand Down
7 changes: 7 additions & 0 deletions rosidl_generator_c/rosidl_generator_c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ def value_to_c(type_, value):
if isinstance(type_, AbstractString):
return '"%s"' % escape_string(value)

if isinstance(type_, AbstractWString):
return 'u"%s"' % escape_wstring(value)

return basic_value_to_c(type_, value)


Expand Down Expand Up @@ -157,3 +160,7 @@ def escape_string(s):
s = s.replace('\\', '\\\\')
s = s.replace('"', r'\"')
return s


def escape_wstring(s):
return escape_string(s)
30 changes: 30 additions & 0 deletions rosidl_generator_c/src/u16string_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ rosidl_generator_c__U16String__assignn(
return true;
}

bool
rosidl_generator_c__U16String__assignn_from_char(
rosidl_generator_c__U16String * str, const char * value, size_t n)
{
// since n represents the number of 8-bit characters it must be an even number
if (n % 2 != 0) {
return false;
}
return rosidl_generator_c__U16String__assignn(
str, (const uint16_t *)value, n / 2);
}

bool
rosidl_generator_c__U16String__assign(
rosidl_generator_c__U16String * str, const uint16_t * value)
Expand All @@ -115,6 +127,24 @@ rosidl_generator_c__U16String__len(const uint16_t * value)
return len;
}

bool
rosidl_generator_c__U16String__resize(
rosidl_generator_c__U16String * str, size_t n)
{
if (!str) {
return false;
}
uint16_t * data = realloc(str->data, (n + 1) * sizeof(uint16_t));
if (!data) {
return false;
}
data[n] = 0;
str->data = data;
str->size = n;
str->capacity = n + 1;
return true;
}

bool
rosidl_generator_c__U16String__Sequence__init(
rosidl_generator_c__U16String__Sequence * sequence, size_t size)
Expand Down
36 changes: 36 additions & 0 deletions rosidl_generator_c/test/test_interfaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "rosidl_generator_c/primitives_sequence_functions.h"
#include "rosidl_generator_c/string_functions.h"
#include "rosidl_generator_c/u16string_functions.h"

#include "rosidl_generator_c/msg/bool.h"
#include "rosidl_generator_c/msg/bounded_array_nested.h"
Expand Down Expand Up @@ -56,13 +57,16 @@
#include "rosidl_generator_c/msg/uint8.h"
#include "rosidl_generator_c/msg/various.h"
#include "rosidl_generator_c/msg/wire.h"
#include "rosidl_generator_c/msg/w_strings.h"

#define TEST_STRING \
"Deep into that darkness peering, long I stood there wondering, fearing"
#define TEST_STRING2 \
"The quick brown fox jumps over the lazy dog."
#define TEST_STRING3 \
"PACK MY BOX WITH FIVE DOZEN LIQUOR JUGS."
#define TEST_WSTRING \
u"Deep into that darkness peering, long I stood there wondering, fearing \u2122"
#define ARRAY_SIZE 7

#define STRINGIFY(x) _STRINGIFY(x)
Expand Down Expand Up @@ -317,6 +321,7 @@ int test_strings(void)
EXPECT_EQ(0, strcmp(strings->empty_string.data, TEST_STRING));
EXPECT_EQ(0, strcmp(strings->def_string.data, "Hello world!"));
EXPECT_EQ(0, strcmp(strings->def_string2.data, "Hello'world!"));
fprintf(stderr, "*%s*\n", strings->def_string3.data);
EXPECT_EQ(0, strcmp(strings->def_string3.data, "Hello\"world!"));
EXPECT_EQ(0, strcmp(strings->def_string4.data, "Hello'world!"));
EXPECT_EQ(0, strcmp(strings->def_string5.data, "Hello\"world!"));
Expand All @@ -333,6 +338,37 @@ int test_strings(void)
return 0;
}

/**
* Test message with different wstring types.
*/
int test_wstrings(void)
{
bool res = false;
rosidl_generator_c__msg__WStrings * wstrings = NULL;

wstrings = rosidl_generator_c__msg__WStrings__create();
EXPECT_NE(wstrings, NULL);

res = rosidl_generator_c__U16String__assign(&wstrings->empty_wstring, TEST_WSTRING);
EXPECT_EQ(true, res);
// EXPECT_EQ(0, strcmp(wstrings->empty_wstring.data, TEST_WSTRING));
// EXPECT_EQ(0, strcmp(wstrings->def_wstring.data, "Hello world!"));
// EXPECT_EQ(0, strcmp(wstrings->def_wstring2.data, "Hello'world!"));
// EXPECT_EQ(0, strcmp(wstrings->def_wstring3.data, "Hello\"world!"));
// EXPECT_EQ(0, strcmp(wstrings->def_wstring4.data, "Hello'world!"));
// EXPECT_EQ(0, strcmp(wstrings->def_wstring5.data, "Hello\"world!"));
// since upper-bound checking is not implemented yet, we restrict the string copying
// TODO(mikaelarguedas) Test string length properly instead of cheating copy
// res = rosidl_generator_c__String__assign(&wstrings->ub_wstring, TEST_WSTRING);
res = rosidl_generator_c__U16String__assignn(&wstrings->ub_wstring, TEST_WSTRING, 24);
EXPECT_EQ(true, res);
// EXPECT_EQ(0, strcmp(wstrings->ub_wstring.data, "Deep into that darknes"));
// EXPECT_EQ(0, strcmp(wstrings->ub_def_wstring.data, "Upper bounded string."));

rosidl_generator_c__msg__WStrings__destroy(wstrings);

return 0;
}

/**
* Test message with different string array types.
Expand Down
2 changes: 2 additions & 0 deletions rosidl_generator_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ if(BUILD_TESTING)
"msg/UnboundedArrayUnbounded.msg"

"msg/Various.msg"

"msg/WString.msg"
)

set(srv_files
Expand Down
Loading

0 comments on commit a4e7463

Please sign in to comment.