Skip to content

Commit

Permalink
Expose type hash on typesupports (rep2011) (#729)
Browse files Browse the repository at this point in the history
* Expose type hash on typesupports

* Change TYPE_VERSION_HASH to TYPE_HASH, fix variable inlining

* Undo the serviceMembers idea

* Re-fix hash definition indentation now that not using defines

* Tweak the separator to match rcl capabilities

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
  • Loading branch information
emersonknapp authored Mar 24, 2023
1 parent 10d0883 commit eac4201
Show file tree
Hide file tree
Showing 19 changed files with 70 additions and 53 deletions.
20 changes: 5 additions & 15 deletions rosidl_generator_c/resource/idl__struct.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@{
from rosidl_generator_c import idl_structure_type_to_c_typename
from rosidl_generator_c import type_hash_to_c_definition
from rosidl_generator_type_description import TYPE_HASH_VAR
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
Expand Down Expand Up @@ -60,10 +61,7 @@ from rosidl_parser.definition import Service
}@
@[for service in content.get_elements_of_type(Service)]@

@{ hash_var = idl_structure_type_to_c_typename(service.namespaced_type) + '__TYPE_VERSION_HASH' }@
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['service'], line_final_backslash=True))
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
static const rosidl_type_hash_t @(idl_structure_type_to_c_typename(service.namespaced_type))__@(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['service']));

@{
TEMPLATE(
Expand Down Expand Up @@ -99,9 +97,7 @@ from rosidl_parser.definition import Action
}@
@[for action in content.get_elements_of_type(Action)]@

@{ hash_var = idl_structure_type_to_c_typename(action.namespaced_type) + '__TYPE_VERSION_HASH' }@
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['action'], line_final_backslash=True))
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
static const rosidl_type_hash_t @(idl_structure_type_to_c_typename(action.namespaced_type))__@(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['action']));

@{
TEMPLATE(
Expand All @@ -127,10 +123,7 @@ TEMPLATE(
type_hash=type_hash['feedback'])
}@

@{ hash_var = idl_structure_type_to_c_typename(action.send_goal_service.namespaced_type) + '__TYPE_VERSION_HASH' }@
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['send_goal_service']['service'], line_final_backslash=True))
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
static const rosidl_type_hash_t @(idl_structure_type_to_c_typename(action.send_goal_service.namespaced_type))__@(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['send_goal_service']['service']));

@{
TEMPLATE(
Expand All @@ -156,10 +149,7 @@ TEMPLATE(
type_hash=type_hash['send_goal_service']['event_message'])
}@

@{ hash_var = idl_structure_type_to_c_typename(action.get_result_service.namespaced_type) + '__TYPE_VERSION_HASH' }@
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['get_result_service']['service'], line_final_backslash=True))
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
static const rosidl_type_hash_t @(idl_structure_type_to_c_typename(action.get_result_service.namespaced_type))__@(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['get_result_service']['service']));

@{
TEMPLATE(
Expand Down
8 changes: 3 additions & 5 deletions rosidl_generator_c/resource/msg__struct.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ from rosidl_generator_c import idl_structure_type_to_c_typename
from rosidl_generator_c import interface_path_to_string
from rosidl_generator_c import type_hash_to_c_definition
from rosidl_generator_c import value_to_c
from rosidl_generator_type_description import TYPE_HASH_VAR
}@
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@# Collect necessary include directives for all members
Expand Down Expand Up @@ -63,11 +64,8 @@ for member in message.structure.members:
@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Type Version Hash for interface
@{ hash_var = idl_structure_type_to_c_typename(message.structure.namespaced_type) + '__TYPE_VERSION_HASH' }@
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['message'], line_final_backslash=True))
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
// Type Hash for interface
static const rosidl_type_hash_t @(idl_structure_type_to_c_typename(message.structure.namespaced_type))__@(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['message']));

// Constants defined in the message
@[for constant in message.constants]@
Expand Down
4 changes: 2 additions & 2 deletions rosidl_generator_c/resource/srv__type_support.c.em
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
@# Included from rosidl_generator_c/resource/srv__type_support.c.em
@{
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
from rosidl_parser.definition import SERVICE_EVENT_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_REQUEST_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_RESPONSE_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_EVENT_MESSAGE_SUFFIX
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
event_type = '__'.join([package_name, *interface_path.parents[0].parts, service.namespaced_type.name]) + SERVICE_EVENT_MESSAGE_SUFFIX
request_type = '__'.join([package_name, *interface_path.parents[0].parts, service.namespaced_type.name]) + SERVICE_REQUEST_MESSAGE_SUFFIX
response_type = '__'.join([package_name, *interface_path.parents[0].parts, service.namespaced_type.name]) + SERVICE_RESPONSE_MESSAGE_SUFFIX
Expand Down
7 changes: 1 addition & 6 deletions rosidl_generator_c/rosidl_generator_c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,25 +223,20 @@ def escape_wstring(s):
return escape_string(s)


def type_hash_to_c_definition(hash_string, *, line_final_backslash=False):
def type_hash_to_c_definition(hash_string, *, indent=2):
"""Generate empy for rosidl_type_hash_t instance with 8 bytes per line for readability."""
bytes_per_row = 8
rows = 4
assert bytes_per_row * rows == RIHS01_HASH_VALUE_SIZE, 'This function is outdated.'
indent = 4 # Uncrustify prefers this indentation
version, value = parse_rihs_string(hash_string)
assert version == 1, 'This function only knows how to generate RIHS01 definitions.'

result = f'{{{version}, {{'
if line_final_backslash:
result += ' \\'
result += '\n'
for row in range(rows):
result += ' ' * (indent + 1)
for i in range(row * bytes_per_row, (row + 1) * bytes_per_row):
result += f' 0x{value[i * 2]}{value[i * 2 + 1]},'
if line_final_backslash:
result += ' \\'
result += '\n'
result += ' ' * indent
result += '}}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ add_dependencies(

set(_target_suffix "__rosidl_generator_cpp")
add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} INTERFACE)
target_compile_features(${rosidl_generate_interfaces_TARGET}${_target_suffix} INTERFACE cxx_std_17)
add_library(${PROJECT_NAME}::${rosidl_generate_interfaces_TARGET}${_target_suffix} ALIAS
${rosidl_generate_interfaces_TARGET}${_target_suffix})
target_include_directories(${rosidl_generate_interfaces_TARGET}${_target_suffix}
Expand Down
3 changes: 2 additions & 1 deletion rosidl_generator_cpp/resource/action__struct.hpp.em
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@# Included from rosidl_generator_cpp/resource/idl__struct.hpp.em
@{
from rosidl_generator_c import type_hash_to_c_definition
from rosidl_generator_type_description import TYPE_HASH_VAR
from rosidl_parser.definition import ACTION_FEEDBACK_MESSAGE_SUFFIX
from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX
from rosidl_parser.definition import ACTION_GOAL_SERVICE_SUFFIX
Expand Down Expand Up @@ -79,7 +80,7 @@ namespace @(ns)
@[end for]@
struct @(action.namespaced_type.name)
{
static constexpr const rosidl_type_hash_t TYPE_VERSION_HASH = @(type_hash_to_c_definition(type_hash['action']));
static constexpr const rosidl_type_hash_t @(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['action'], indent=4));

/// The goal message defined in the action definition.
using Goal = @(action_name)@(ACTION_GOAL_SUFFIX);
Expand Down
6 changes: 3 additions & 3 deletions rosidl_generator_cpp/resource/msg__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ from rosidl_generator_cpp import escape_string
from rosidl_generator_cpp import escape_wstring
from rosidl_generator_cpp import msg_type_to_cpp
from rosidl_generator_cpp import MSG_TYPE_TO_CPP
from rosidl_generator_type_description import TYPE_HASH_VAR
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractString
from rosidl_parser.definition import AbstractWString
Expand Down Expand Up @@ -102,8 +103,7 @@ struct @(message.structure.namespaced_type.name)_
{
using Type = @(message.structure.namespaced_type.name)_<ContainerAllocator>;

// Type Version Hash for interface
constexpr static const rosidl_type_hash_t TYPE_VERSION_HASH = @(type_hash_to_c_definition(type_hash['message']));
constexpr static const rosidl_type_hash_t @(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['message'], indent=4));

@{
# The creation of the constructors for messages is a bit complicated. The goal
Expand Down Expand Up @@ -362,7 +362,7 @@ using @(message.structure.namespaced_type.name) =
@(message_typename)_<std::allocator<void>>;

template<class ContainerAllocator>
constexpr const rosidl_type_hash_t @(message.structure.namespaced_type.name)_<ContainerAllocator>::TYPE_VERSION_HASH;
constexpr const rosidl_type_hash_t @(message.structure.namespaced_type.name)_<ContainerAllocator>::@(TYPE_HASH_VAR);

// constant definitions
@[for c in message.constants]@
Expand Down
12 changes: 8 additions & 4 deletions rosidl_generator_cpp/resource/srv__struct.hpp.em
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
@# Included from rosidl_generator_cpp/resource/idl__struct.hpp.em
@{
from rosidl_generator_c import type_hash_to_c_definition
from rosidl_generator_type_description import TYPE_HASH_VAR
from rosidl_parser.definition import SERVICE_EVENT_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_REQUEST_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_RESPONSE_MESSAGE_SUFFIX
}@
@{
TEMPLATE(
Expand Down Expand Up @@ -37,11 +41,11 @@ struct @(service.namespaced_type.name)
@{
service_typename = '::'.join(service.namespaced_type.namespaced_name())
}@
static constexpr const rosidl_type_hash_t TYPE_VERSION_HASH = @(type_hash_to_c_definition(type_hash['service']));
static constexpr const rosidl_type_hash_t @(TYPE_HASH_VAR) = @(type_hash_to_c_definition(type_hash['service'], indent=4));

using Request = @(service_typename)_Request;
using Response = @(service_typename)_Response;
using Event = @(service_typename)_Event;
using Request = @(service_typename)@(SERVICE_REQUEST_MESSAGE_SUFFIX);
using Response = @(service_typename)@(SERVICE_RESPONSE_MESSAGE_SUFFIX);
using Event = @(service_typename)@(SERVICE_EVENT_MESSAGE_SUFFIX);
};
@
@[for ns in reversed(service.namespaced_type.namespaces)]@
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_type_description/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This generator serializes ROS 2 interface descriptions (message, service, action) to a common format and uses SHA256 to hash that representation into a unique hash for each type.

The SHA256 hashes generated by this package must match those generated by `rcl_calculate_type_version_hash`. The `.json` files generated must, therefore, match the result of `rcl_type_description_to_hashable_json`.
The SHA256 hashes generated by this package must match those generated by `rcl_calculate_type_hash`. The `.json` files generated must, therefore, match the result of `rcl_type_description_to_hashable_json`.

## Generated files

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
RIHS01_HASH_VALUE_SIZE = 32
RIHS01_PATTERN = re.compile(r'RIHS([0-9a-f]{2})_([0-9a-f]{64})')

# Used by code generators to create type hash variable names
TYPE_HASH_VAR = 'TYPE_HASH'


def generate_type_hash(generator_arguments_file: str) -> List[str]:
with open(generator_arguments_file, 'r') as f:
Expand Down Expand Up @@ -461,7 +464,8 @@ def _calculate_hash_tree(self) -> dict:
check_circular=True,
allow_nan=False,
indent=None,
separators=(',', ': '),
# note: libyaml in C doesn't allow for tweaking these separators, this is its builtin
separators=(', ', ': '),
sort_keys=False
)
sha = hashlib.sha256()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "rosidl_runtime_c/message_type_support_struct.h"
#include "rosidl_runtime_c/service_type_support_struct.h"
#include "rosidl_runtime_c/type_hash.h"
#include "rosidl_runtime_c/visibility_control.h"
#include "rosidl_typesupport_interface/macros.h"

Expand All @@ -38,6 +39,8 @@ struct rosidl_action_type_support_t
const rosidl_service_type_support_t * cancel_service_type_support;
const rosidl_message_type_support_t * feedback_message_type_support;
const rosidl_message_type_support_t * status_message_type_support;
/// Hash of the action's description
const rosidl_type_hash_t * type_hash;
};

/// Get the action type support given a provided action and package.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef ROSIDL_RUNTIME_C__MESSAGE_TYPE_SUPPORT_STRUCT_H_
#define ROSIDL_RUNTIME_C__MESSAGE_TYPE_SUPPORT_STRUCT_H_

#include "rosidl_runtime_c/type_hash.h"
#include "rosidl_runtime_c/visibility_control.h"
#include "rosidl_typesupport_interface/macros.h"

Expand All @@ -37,6 +38,8 @@ struct rosidl_message_type_support_t
const void * data;
/// Pointer to the message type support handler function
rosidl_message_typesupport_handle_function func;
/// Hash of the message's description
const rosidl_type_hash_t * type_hash;
};

/// Get the message type support handle specific to this identifier.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "rcutils/allocator.h"
#include "rosidl_runtime_c/message_type_support_struct.h"
#include "rosidl_runtime_c/type_hash.h"
#include "rosidl_runtime_c/visibility_control.h"

#include "rosidl_typesupport_interface/macros.h"
Expand Down Expand Up @@ -81,12 +82,18 @@ struct rosidl_service_type_support_t
const void * data;
/// Pointer to the service type support handler function
rosidl_service_typesupport_handle_function func;
/// Service request message typesupport
const rosidl_message_type_support_t * request_typesupport;
/// Service response message typesupport
const rosidl_message_type_support_t * response_typesupport;
/// Service event message typesupport
const rosidl_message_type_support_t * event_typesupport;
/// Pointer to function to create the introspection message
rosidl_event_message_create_handle_function_function event_message_create_handle_function;
/// Pointer to function to finalize the introspection message
rosidl_event_message_destroy_handle_function_function event_message_destroy_handle_function;
/// Service event message typesupport
const rosidl_message_type_support_t * event_typesupport;
/// Hash of the service's description
const rosidl_type_hash_t * type_hash;
};

/// Get the service type support handle specific to this identifier.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ typedef struct rosidl_typesupport_introspection_c__MessageMembers_s
const char * message_namespace_;
/// The name of the interface, e.g. "Int16"
const char * message_name_;
/// Hashed value of the interface description
const rosidl_type_hash_t type_hash_;
/// The number of fields in the interface
uint32_t member_count_;
/// The size of the interface structure in memory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
@{
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
from rosidl_generator_c import idl_structure_type_to_c_include_prefix
from rosidl_generator_c import idl_structure_type_to_c_typename
from rosidl_generator_type_description import TYPE_HASH_VAR
from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractSequence
Expand Down Expand Up @@ -270,7 +272,6 @@ for index, member in enumerate(message.structure.members):
static const rosidl_typesupport_introspection_c__MessageMembers @(function_prefix)__@(message.structure.namespaced_type.name)_message_members = {
"@('__'.join([package_name] + list(interface_path.parents[0].parts)))", // message namespace
"@(message.structure.namespaced_type.name)", // message name
@('__'.join(message.structure.namespaced_type.namespaced_name()))__TYPE_VERSION_HASH__INIT,
@(len(message.structure.members)), // number of fields
sizeof(@('__'.join([package_name] + list(interface_path.parents[0].parts) + [message.structure.namespaced_type.name]))),
@(function_prefix)__@(message.structure.namespaced_type.name)_message_member_array, // message members
Expand All @@ -284,6 +285,7 @@ static rosidl_message_type_support_t @(function_prefix)__@(message.structure.nam
0,
&@(function_prefix)__@(message.structure.namespaced_type.name)_message_members,
get_message_typesupport_handle_function,
&@(idl_structure_type_to_c_typename(message.structure.namespaced_type))__@(TYPE_HASH_VAR),
};

ROSIDL_TYPESUPPORT_INTROSPECTION_C_EXPORT_@(package_name)
Expand Down
16 changes: 12 additions & 4 deletions rosidl_typesupport_introspection_c/resource/srv__type_support.c.em
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ TEMPLATE(
}@

@{
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
from rosidl_generator_c import idl_structure_type_to_c_typename
from rosidl_generator_type_description import TYPE_HASH_VAR
from rosidl_parser.definition import SERVICE_EVENT_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_REQUEST_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_RESPONSE_MESSAGE_SUFFIX
from rosidl_parser.definition import SERVICE_EVENT_MESSAGE_SUFFIX
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
include_base = '/'.join(include_parts)
Expand All @@ -37,7 +39,10 @@ header_files = [
'rosidl_typesupport_introspection_c/service_introspection.h',
]

message_function_prefix = '__'.join([package_name] + list(interface_path.parents[0].parts) + [service.namespaced_type.name]) + f'{SERVICE_EVENT_MESSAGE_SUFFIX}__rosidl_typesupport_introspection_c'
message_function_prefix = '__'.join([package_name] + list(interface_path.parents[0].parts) + [service.namespaced_type.name])
request_message_function_prefix = message_function_prefix + f'{SERVICE_REQUEST_MESSAGE_SUFFIX}__rosidl_typesupport_introspection_c'
response_message_function_prefix = message_function_prefix + f'{SERVICE_RESPONSE_MESSAGE_SUFFIX}__rosidl_typesupport_introspection_c'
event_message_function_prefix = message_function_prefix + f'{SERVICE_EVENT_MESSAGE_SUFFIX}__rosidl_typesupport_introspection_c'
function_prefix = '__'.join(include_parts) + '__rosidl_typesupport_introspection_c'
}@
@[for header_file in header_files]@
Expand Down Expand Up @@ -71,6 +76,9 @@ static rosidl_service_type_support_t @(function_prefix)__@(service.namespaced_ty
0,
&@(function_prefix)__@(service.namespaced_type.name)_service_members,
get_service_typesupport_handle_function,
&@(request_message_function_prefix)__@(service.namespaced_type.name)@(SERVICE_REQUEST_MESSAGE_SUFFIX)_message_type_support_handle,
&@(response_message_function_prefix)__@(service.namespaced_type.name)@(SERVICE_RESPONSE_MESSAGE_SUFFIX)_message_type_support_handle,
&@(event_message_function_prefix)__@(service.namespaced_type.name)@(SERVICE_EVENT_MESSAGE_SUFFIX)_message_type_support_handle,
ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_CREATE_EVENT_MESSAGE_SYMBOL_NAME(
rosidl_typesupport_c,
@(',\n '.join(service.namespaced_type.namespaced_name()))
Expand All @@ -79,7 +87,7 @@ static rosidl_service_type_support_t @(function_prefix)__@(service.namespaced_ty
rosidl_typesupport_c,
@(',\n '.join(service.namespaced_type.namespaced_name()))
),
&@(message_function_prefix)__@(service.namespaced_type.name)@(SERVICE_EVENT_MESSAGE_SUFFIX)_message_type_support_handle,
&@(idl_structure_type_to_c_typename(service.namespaced_type))__@(TYPE_HASH_VAR),
};

// Forward declaration of request/response type support functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ typedef struct ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC MessageMembers_s
const char * message_namespace_;
/// The name of the interface, e.g. "Int16"
const char * message_name_;
/// Hashed value of the interface description
const rosidl_type_hash_t type_hash_;
/// The number of fields in the interface
uint32_t member_count_;
/// The size of the interface structure in memory
Expand Down
Loading

0 comments on commit eac4201

Please sign in to comment.