Skip to content

Commit ed15a9a

Browse files
committed
Release v2.2
2 parents 9ce305d + a90f8c3 commit ed15a9a

28 files changed

+798
-21
lines changed

comms/doc/page_define_prot.dox

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,130 @@
10251025
/// };
10261026
/// @endcode
10271027
///
1028+
/// @section page_define_prot_field_aliases Aliases to Field Names
1029+
/// When the communication protocol evolves and new versions of it are being released,
1030+
/// it may happen that some fields get renamed to give them a different or refined
1031+
/// meaning. Simple change of the name may result in old client code not being
1032+
/// able to compile with new versions of the protocol definition library. To
1033+
/// help with such case the @b COMMS library provides several macros that can generate
1034+
/// alias names for renamed fields.
1035+
///
1036+
/// @subsection page_define_prot_field_aliases_messages Aliases to Field Names Inside Message Definition
1037+
/// The @b COMMS library provides @ref COMMS_MSG_FIELD_ALIAS()
1038+
/// macro, which is expected to be used after @ref COMMS_MSG_FIELDS_ACCESS() one when new
1039+
/// message class is being defined.
1040+
/// As an example let's change the @b value3 from the example in the
1041+
/// @ref page_define_prot_message_base_field_names section to be @b newValue3.
1042+
/// @code
1043+
/// template <typename TMessage>
1044+
/// class Message1 : public comms::MessageBase<...>
1045+
/// {
1046+
/// public:
1047+
/// // Provide names for the fields
1048+
/// COMMS_MSG_FIELDS_ACCESS(value1, value2, newValue3);
1049+
/// COMMS_MSG_FIELD_ALIAS(value3, newValue3);
1050+
/// };
1051+
/// @endcode
1052+
/// The usage of @ref COMMS_MSG_FIELD_ALIAS() above generates the following convenience access functions:
1053+
/// @code
1054+
/// template <typename TMessage>
1055+
/// class Message1 : public comms::MessageBase<...>
1056+
/// {
1057+
/// public:
1058+
/// // Provide names for the fields
1059+
/// COMMS_MSG_FIELDS_ACCESS(value1, value2, newValue3);
1060+
///
1061+
/// // Access to "newValue3" via "value3" name
1062+
/// auto field_value3() -> decltype(field_newValue3())
1063+
/// {
1064+
/// return field_newValue3();
1065+
/// }
1066+
///
1067+
/// // Const access to "newValue3" via "value3" name
1068+
/// auto field_value3() const -> decltype(field_newValue3())
1069+
/// {
1070+
/// return field_newValue3();
1071+
/// }
1072+
/// };
1073+
/// @endcode
1074+
/// In this case the old client code that tries to access appropriate field
1075+
/// using @b field_value3() access function will still work after renaming
1076+
/// takes place.
1077+
///
1078+
/// Another common case is when some field (usually @ref comms::field::IntValue
1079+
/// or @ref comms::field::EnumValue) has a limited range of possible values
1080+
/// and in order to save on some I/O traffic, the developer decides to split
1081+
/// the value storage into multiple small parts and make it a
1082+
/// @ref comms::field::Bitfield instead. In order to keep old client code compiling
1083+
/// and working the @ref COMMS_MSG_FIELD_ALIAS() may be used:
1084+
/// @code
1085+
/// template <typename TMessage>
1086+
/// class Message1 : public comms::MessageBase<...>
1087+
/// {
1088+
/// public:
1089+
/// // Provide names for the fields
1090+
/// COMMS_MSG_FIELDS_ACCESS(value1, value2, newValue3);
1091+
/// COMMS_MSG_FIELD_ALIAS(value3, newValue3, member1);
1092+
/// };
1093+
/// @endcode
1094+
/// The usage of @ref COMMS_MSG_FIELD_ALIAS() above generates the following convenience access functions:
1095+
/// @code
1096+
/// template <typename TMessage>
1097+
/// class Message1 : public comms::MessageBase<...>
1098+
/// {
1099+
/// public:
1100+
/// // Provide names for the fields
1101+
/// COMMS_MSG_FIELDS_ACCESS(value1, value2, newValue3);
1102+
///
1103+
/// // Access to "newValue3.member1" via "value3" name
1104+
/// auto field_value3() -> decltype(field_newValue3().field_member1())
1105+
/// {
1106+
/// return field_newValue3().field_member1();
1107+
/// }
1108+
///
1109+
/// // Const access to "newValue3.member1" via "value3" name
1110+
/// auto field_value3() const -> decltype(field_newValue3().field_member1())
1111+
/// {
1112+
/// return field_newValue3().field_member1();
1113+
/// }
1114+
/// };
1115+
/// @endcode
1116+
///
1117+
/// @subsection page_define_prot_field_aliases_bundles Aliases to Field Names Inside Bundle Fields
1118+
/// Similar to defining aliases to message fields, @b COMMS library provides an ability to define
1119+
/// aliases within @ref comms::field::Bundle "bundle" field definition using
1120+
/// @ref COMMS_FIELD_ALIAS() macro.
1121+
/// @code
1122+
/// class MyBundle : public comms::field::Bundle<...>
1123+
/// {
1124+
/// public:
1125+
/// COMMS_FIELD_MEMBERS_ACCESS(member1, member2, member3);
1126+
/// COMMS_FIELD_ALIAS(otherMem1Name, member1);
1127+
/// COMMS_FIELD_ALIAS(otherMem2Name, member2);
1128+
/// };
1129+
/// @endcode
1130+
///
1131+
/// @subsection page_define_prot_field_aliases_interfaces Aliases to Extra Transport Field Names Inside Interface
1132+
/// The @ref page_define_prot_interface class definition may have
1133+
/// @ref page_define_prot_interface_extra_transport. Aliasing between the
1134+
/// extra transport fields can be defined using @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS()
1135+
/// macro.
1136+
/// @code
1137+
/// template <typename... TOptions>
1138+
/// class Message : public
1139+
/// comms::Message<
1140+
/// comms::option::def::BigEndian,
1141+
/// comms::option::def::MsgIdType<MsgId>,
1142+
/// comms::option::def::ExtraTransportFields<MyExtraTransportFields>,
1143+
/// TOptions...
1144+
/// >
1145+
/// {
1146+
/// public:
1147+
/// COMMS_MSG_TRANSPORT_FIELDS_ACCESS(version, flags);
1148+
/// COMMS_MSG_TRANSPORT_FIELD_ALIAS(otherFlagsName, flags);
1149+
/// };
1150+
/// @endcode
1151+
///
10281152
/// @section page_define_prot_lenth_verification Extra Compile Time Checks
10291153
/// Quite often it is obvious from the protocol specification what minimal length
10301154
/// of the serialised message contents is expected to be, and if there are not

comms/include/comms/Field.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "comms/details/FieldBase.h"
2727
#include "comms/details/macro_common.h"
2828
#include "comms/details/fields_access.h"
29+
#include "comms/details/field_alias.h"
2930

3031
namespace comms
3132
{
@@ -501,5 +502,13 @@ class Field : public details::FieldBase<TOptions...>
501502
COMMS_EXPAND(COMMS_DO_FIELD_ACC_FUNC_NOTEMPLATE(__VA_ARGS__))
502503
#endif // #ifdef FOR_DOXYGEN_DOC_ONLY
503504

505+
/// @brief Generate convinience alias access member functions for other
506+
/// member fields.
507+
/// @details Same as @ref COMMS_MSG_FIELDS_ACCESS() but applicable to
508+
/// @ref comms::field::Bundle field.
509+
/// @pre The macro @ref COMMS_FIELD_MEMBERS_ACCESS() needs to be used before
510+
/// @ref COMMS_FIELD_ALIAS() to define convenience access functions.
511+
#define COMMS_FIELD_ALIAS(f_, ...) COMMS_DO_ALIAS(field_, f_, __VA_ARGS__)
512+
504513
} // namespace comms
505514

comms/include/comms/Message.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "comms/details/transport_fields_access.h"
3434
#include "comms/details/detect.h"
3535
#include "comms/details/MessageIdTypeRetriever.h"
36+
#include "comms/details/field_alias.h"
3637

3738
namespace comms
3839
{
@@ -685,3 +686,101 @@ using MessageIdType =
685686
} \
686687
COMMS_EXPAND(COMMS_DO_TRANSPORT_FIELD_ACC_FUNC(TransportFields, transportFields(), __VA_ARGS__))
687688

689+
/// @brief Generate convinience alias access member functions for extra
690+
/// member transport fields.
691+
/// @details The @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS() macro generates convenience
692+
/// access member functions for extra transport fields. Sometimes the fields
693+
/// may get renamed or moved to be a member of other fields, like
694+
/// @ref comms::field::Bundle or @ref comms::field::Bitfield. In such
695+
/// case the compilation of the existing client code (that already
696+
/// uses published protocol definition) may fail. To avoid such scenarios
697+
/// and make the transition to newer versions of the protocol easier,
698+
/// the @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS() macro can be used to create alias
699+
/// to other fields. For example, let's assume that some common interface class was defined:
700+
/// like this.
701+
/// @code
702+
/// class MyInterface : public public comms::Message<...>
703+
/// {
704+
/// public:
705+
/// COMMS_MSG_TRANSPORT_FIELDS_ACCESS(name1, name2, name3);
706+
/// };
707+
/// @endcode
708+
/// In the future versions of the protocol "name3" was renamed to
709+
/// "newName3". To keep the existing code (that uses "name3" name)
710+
/// compiling it is possible to create an alias access function(s)
711+
/// with:
712+
/// @code
713+
/// class MyInterface : public public comms::Message<...>
714+
/// {
715+
/// public:
716+
/// COMMS_MSG_TRANSPORT_FIELDS_ACCESS(name1, name2, newName3);
717+
/// COMMS_MSG_TRANSPORT_FIELD_ALIAS(name3, newName3);
718+
/// };
719+
/// @endcode
720+
/// The usage of @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS() in the code above is
721+
/// equivalent to having the following functions defined:
722+
/// @code
723+
/// class MyInterface : public public comms::Message<...>
724+
/// {
725+
/// public:
726+
/// ...
727+
/// auto transportField_name3() -> decltype(transportField_newName3())
728+
/// {
729+
/// return transportField_newName3();
730+
/// }
731+
///
732+
/// auto transportField_name3() const -> decltype(transportField_newName3())
733+
/// {
734+
/// return transportField_newName3();
735+
/// }
736+
/// };
737+
/// @endcode
738+
/// Another example would be a replacing a @ref comms::field::IntValue
739+
/// with @ref comms::field::Bitfield in the future version of the
740+
/// protocol. It can happen when the developer decides to split
741+
/// the used storage into multiple values (because the range
742+
/// of the used/valid values allows so). In order to keep the old client
743+
/// code compiling, the access to the replaced field needs to be
744+
/// an alias to the first member of the @ref comms::field::Bitfield.
745+
/// In this case the usage of @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS() will
746+
/// look like this:
747+
/// @code
748+
/// class MyInterface : public public comms::Message<...>
749+
/// {
750+
/// public:
751+
/// COMMS_MSG_TRANSPORT_FIELDS_ACCESS(name1, name2, newName3);
752+
/// COMMS_MSG_TRANSPORT_FIELD_ALIAS(name3, newName3, member1);
753+
/// };
754+
/// @endcode
755+
/// The usage of @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS() in the code above is
756+
/// equivalent to having the following functions defined:
757+
/// @code
758+
/// class MyInterface : public public comms::Message<...>
759+
/// {
760+
/// public:
761+
/// ...
762+
/// auto transportField_name3() -> decltype(transportField_newName3().field_member1())
763+
/// {
764+
/// return field_newName3().field_member1();
765+
/// }
766+
///
767+
/// auto transportField_name3() const -> decltype(transportField_newName3().field_member1())
768+
/// {
769+
/// return transportField_newName3().field_member1();
770+
/// }
771+
/// };
772+
/// @endcode
773+
/// @param[in] f_ Alias field name.
774+
/// @param[in] ... List of fields' names.
775+
/// @pre The macro @ref COMMS_MSG_TRANSPORT_FIELDS_ACCESS() needs to be used before
776+
/// @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS() to define convenience access functions.
777+
/// @related comms::Message
778+
/// @see @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS_NOTEMPLATE()
779+
#define COMMS_MSG_TRANSPORT_FIELD_ALIAS(f_, ...) COMMS_EXPAND(COMMS_DO_ALIAS(transportField_, f_, __VA_ARGS__))
780+
781+
/// @brief Generate convinience alias access member functions for extra
782+
/// member transport fields in non template interface classes.
783+
/// @details Similar to @ref COMMS_MSG_TRANSPORT_FIELD_ALIAS, but
784+
/// needs to be used in @b non-template interface class to
785+
/// allow compilation with gcc-4.8
786+
#define COMMS_MSG_TRANSPORT_FIELD_ALIAS_NOTEMPLATE(f_, ...) COMMS_EXPAND(COMMS_DO_ALIAS_NOTEMPLATE(transportField_, f_, __VA_ARGS__))

comms/include/comms/MessageBase.h

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020

2121
#pragma once
2222

23-
#include "details/MessageImplBuilder.h"
24-
#include "details/macro_common.h"
25-
#include "details/fields_access.h"
26-
#include "details/detect.h"
23+
#include "comms/details/MessageImplBuilder.h"
24+
#include "comms/details/macro_common.h"
25+
#include "comms/details/fields_access.h"
26+
#include "comms/details/detect.h"
27+
#include "comms/details/field_alias.h"
2728

2829
namespace comms
2930
{
@@ -934,3 +935,94 @@ constexpr bool isMessageBase()
934935
return val; \
935936
} \
936937
COMMS_EXPAND(COMMS_DO_FIELD_ACC_FUNC(AllFields, fields(), __VA_ARGS__))
938+
939+
/// @brief Generate convinience alias access member functions for other
940+
/// member fields.
941+
/// @details The @ref COMMS_MSG_FIELDS_ACCESS() macro generates convenience
942+
/// access member functions for member fields. Sometimes the fields
943+
/// may get renamed or moved to be a member of other fields, like
944+
/// @ref comms::field::Bundle or @ref comms::field::Bitfield. In such
945+
/// case the compilation of the existing client code (that already
946+
/// uses published protocol definition) may fail. To avoid such scenarios
947+
/// and make the transition to newer versions of the protocol easier,
948+
/// the @ref COMMS_MSG_FIELD_ALIAS() macro can be used to create alias
949+
/// to other fields. For example, let's assume that some message class was defined:
950+
/// like this.
951+
/// @code
952+
/// class Message1 : public comms::MessageBase<...>
953+
/// {
954+
/// public:
955+
/// COMMS_MSG_FIELDS_ACCESS(name1, name2, name3);
956+
/// };
957+
/// @endcode
958+
/// In the future versions of the protocol "name3" was renamed to
959+
/// "newName3". To keep the existing code (that uses "name3" name)
960+
/// compiling it is possible to create an alias access function(s)
961+
/// with:
962+
/// @code
963+
/// class Message1 : public comms::MessageBase<...>
964+
/// {
965+
/// public:
966+
/// COMMS_MSG_FIELDS_ACCESS(name1, name2, newName3);
967+
/// COMMS_MSG_FIELD_ALIAS(name3, newName3);
968+
/// };
969+
/// @endcode
970+
/// The usage of @ref COMMS_MSG_FIELD_ALIAS() in the code above is
971+
/// equivalent to having the following functions defined:
972+
/// @code
973+
/// class Message1 : public comms::MessageBase<...>
974+
/// {
975+
/// public:
976+
/// ...
977+
/// auto field_name3() -> decltype(field_newName3())
978+
/// {
979+
/// return field_newName3();
980+
/// }
981+
///
982+
/// auto field_name3() const -> decltype(field_newName3())
983+
/// {
984+
/// return field_newName3();
985+
/// }
986+
/// };
987+
/// @endcode
988+
/// Another example would be a replacing a @ref comms::field::IntValue
989+
/// with @ref comms::field::Bitfield in the future version of the
990+
/// protocol. It can happen when the developer decides to split
991+
/// the used storage into multiple values (because the range
992+
/// of the used/valid values allows so). In order to keep the old client
993+
/// code compiling, the access to the replaced field needs to be
994+
/// an alias to the first member of the @ref comms::field::Bitfield.
995+
/// In this case the usage of @ref COMMS_MSG_FIELD_ALIAS() will
996+
/// look like this:
997+
/// @code
998+
/// class Message1 : public comms::MessageBase<...>
999+
/// {
1000+
/// public:
1001+
/// COMMS_MSG_FIELDS_ACCESS(name1, name2, newName3);
1002+
/// COMMS_MSG_FIELD_ALIAS(name3, newName3, member1);
1003+
/// };
1004+
/// @endcode
1005+
/// The usage of @ref COMMS_MSG_FIELD_ALIAS() in the code above is
1006+
/// equivalent to having the following functions defined:
1007+
/// @code
1008+
/// class Message1 : public comms::MessageBase<...>
1009+
/// {
1010+
/// public:
1011+
/// ...
1012+
/// auto field_name3() -> decltype(field_newName3().field_member1())
1013+
/// {
1014+
/// return field_newName3().field_member1();
1015+
/// }
1016+
///
1017+
/// auto field_name3() const -> decltype(field_newName3().field_member1())
1018+
/// {
1019+
/// return field_newName3().field_member1();
1020+
/// }
1021+
/// };
1022+
/// @endcode
1023+
/// @param[in] f_ Alias field name.
1024+
/// @param[in] ... List of fields' names.
1025+
/// @pre The macro @ref COMMS_MSG_FIELDS_ACCESS() needs to be used before
1026+
/// @ref COMMS_MSG_FIELD_ALIAS() to define convenience access functions.
1027+
/// @related comms::MessageBase
1028+
#define COMMS_MSG_FIELD_ALIAS(f_, ...) COMMS_DO_ALIAS(field_, f_, __VA_ARGS__)

0 commit comments

Comments
 (0)