EnumSerializer.h (6155B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef __IPC_GLUE_ENUMSERIALIZER_H__ 8 #define __IPC_GLUE_ENUMSERIALIZER_H__ 9 10 #include "CrashAnnotations.h" 11 #include "chrome/common/ipc_message_utils.h" 12 #include "mozilla/Assertions.h" 13 #include "mozilla/IntegerTypeTraits.h" 14 #include "nsExceptionHandler.h" 15 #include "nsLiteralString.h" 16 #include "nsString.h" 17 #include "nsTLiteralString.h" 18 19 class PickleIterator; 20 21 namespace IPC { 22 class Message; 23 class MessageReader; 24 class MessageWriter; 25 } // namespace IPC 26 27 #ifdef _MSC_VER 28 # pragma warning(disable : 4800) 29 #endif 30 31 namespace IPC { 32 33 /** 34 * Generic enum serializer. 35 * 36 * Consider using the specializations below, such as ContiguousEnumSerializer. 37 * 38 * This is a generic serializer for any enum type used in IPDL. 39 * Programmers can define ParamTraits<E> for enum type E by deriving 40 * EnumSerializer<E, MyEnumValidator> where MyEnumValidator is a struct 41 * that has to define a static IsLegalValue function returning whether 42 * a given value is a legal value of the enum type at hand. 43 * 44 * \sa https://developer.mozilla.org/en/IPDL/Type_Serialization 45 */ 46 template <typename E, typename EnumValidator> 47 struct EnumSerializer { 48 typedef E paramType; 49 50 // XXX(Bug 1690343) Should this be changed to 51 // std::make_unsigned_t<std::underlying_type_t<paramType>>, to make this more 52 // consistent with the type used for validating values? 53 typedef typename mozilla::UnsignedStdintTypeForSize<sizeof(paramType)>::Type 54 uintParamType; 55 56 static void Write(MessageWriter* aWriter, const paramType& aValue) { 57 // XXX This assertion is somewhat meaningless at least for E that don't have 58 // a fixed underlying type: if aValue weren't a legal value, we would 59 // already have UB where this function is called. 60 MOZ_RELEASE_ASSERT(EnumValidator::IsLegalValue( 61 static_cast<std::underlying_type_t<paramType>>(aValue))); 62 WriteParam(aWriter, uintParamType(aValue)); 63 } 64 65 static bool Read(MessageReader* aReader, paramType* aResult) { 66 uintParamType value; 67 if (!ReadParam(aReader, &value)) { 68 CrashReporter::RecordAnnotationCString( 69 CrashReporter::Annotation::IPCReadErrorReason, "Bad iter"); 70 return false; 71 } 72 if (!EnumValidator::IsLegalValue(value)) { 73 CrashReporter::RecordAnnotationCString( 74 CrashReporter::Annotation::IPCReadErrorReason, "Illegal value"); 75 return false; 76 } 77 *aResult = paramType(value); 78 return true; 79 } 80 }; 81 82 template <typename E, E MinLegal, E HighBound> 83 class ContiguousEnumValidator { 84 // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8: 85 // "comparison of unsigned expression >= 0 is always true" 86 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 87 template <typename T> 88 static bool IsLessThanOrEqual(T a, T b) { 89 return a <= b; 90 } 91 92 public: 93 using IntegralType = std::underlying_type_t<E>; 94 static constexpr auto kMinLegalIntegral = static_cast<IntegralType>(MinLegal); 95 static constexpr auto kHighBoundIntegral = 96 static_cast<IntegralType>(HighBound); 97 98 static bool IsLegalValue(const IntegralType e) { 99 return IsLessThanOrEqual(kMinLegalIntegral, e) && e < kHighBoundIntegral; 100 } 101 }; 102 103 template <typename E, E MinLegal, E MaxLegal> 104 class ContiguousEnumValidatorInclusive { 105 // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8: 106 // "comparison of unsigned expression >= 0 is always true" 107 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 108 template <typename T> 109 static bool IsLessThanOrEqual(T a, T b) { 110 return a <= b; 111 } 112 113 public: 114 using IntegralType = std::underlying_type_t<E>; 115 static constexpr auto kMinLegalIntegral = static_cast<IntegralType>(MinLegal); 116 static constexpr auto kMaxLegalIntegral = static_cast<IntegralType>(MaxLegal); 117 118 static bool IsLegalValue(const IntegralType e) { 119 return IsLessThanOrEqual(kMinLegalIntegral, e) && e <= kMaxLegalIntegral; 120 } 121 }; 122 123 template <typename E, E AllBits> 124 struct BitFlagsEnumValidator { 125 static bool IsLegalValue(const std::underlying_type_t<E> e) { 126 return (e & static_cast<std::underlying_type_t<E>>(AllBits)) == e; 127 } 128 }; 129 130 /** 131 * Specialization of EnumSerializer for enums with contiguous enum values. 132 * 133 * Provide two values: MinLegal, HighBound. An enum value x will be 134 * considered legal if MinLegal <= x < HighBound. 135 * 136 * For example, following is definition of serializer for enum type FOO. 137 * \code 138 * enum FOO { FOO_FIRST, FOO_SECOND, FOO_LAST, NUM_FOO }; 139 * 140 * template <> 141 * struct ParamTraits<FOO>: 142 * public ContiguousEnumSerializer<FOO, FOO_FIRST, NUM_FOO> {}; 143 * \endcode 144 * FOO_FIRST, FOO_SECOND, and FOO_LAST are valid value. 145 */ 146 template <typename E, E MinLegal, E HighBound> 147 struct ContiguousEnumSerializer 148 : EnumSerializer<E, ContiguousEnumValidator<E, MinLegal, HighBound>> {}; 149 150 /** 151 * This is similar to ContiguousEnumSerializer, but the last template 152 * parameter is expected to be the highest legal value, rather than a 153 * sentinel value. This is intended to support enumerations that don't 154 * have sentinel values. 155 */ 156 template <typename E, E MinLegal, E MaxLegal> 157 struct ContiguousEnumSerializerInclusive 158 : EnumSerializer<E, 159 ContiguousEnumValidatorInclusive<E, MinLegal, MaxLegal>> { 160 }; 161 162 /** 163 * Specialization of EnumSerializer for enums representing bit flags. 164 * 165 * Provide one value: AllBits. An enum value x will be 166 * considered legal if (x & AllBits) == x; 167 * 168 * Example: 169 * \code 170 * enum FOO { 171 * FOO_FIRST = 1 << 0, 172 * FOO_SECOND = 1 << 1, 173 * FOO_LAST = 1 << 2, 174 * ALL_BITS = (1 << 3) - 1 175 * }; 176 * 177 * template <> 178 * struct ParamTraits<FOO>: 179 * public BitFlagsEnumSerializer<FOO, FOO::ALL_BITS> {}; 180 * \endcode 181 */ 182 template <typename E, E AllBits> 183 struct BitFlagsEnumSerializer 184 : EnumSerializer<E, BitFlagsEnumValidator<E, AllBits>> {}; 185 186 } /* namespace IPC */ 187 188 #endif /* __IPC_GLUE_ENUMSERIALIZER_H__ */