summaryrefslogtreecommitdiffstats
path: root/ipc/glue/EnumSerializer.h
blob: 13c1de3841ed561697e50b42e06505406602230d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __IPC_GLUE_ENUMSERIALIZER_H__
#define __IPC_GLUE_ENUMSERIALIZER_H__

#include "CrashAnnotations.h"
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/Assertions.h"
#include "mozilla/IntegerTypeTraits.h"
#include "nsExceptionHandler.h"
#include "nsLiteralString.h"
#include "nsString.h"
#include "nsTLiteralString.h"

class PickleIterator;

namespace IPC {
class Message;
class MessageReader;
class MessageWriter;
}  // namespace IPC

#ifdef _MSC_VER
#  pragma warning(disable : 4800)
#endif

namespace IPC {

/**
 * Generic enum serializer.
 *
 * Consider using the specializations below, such as ContiguousEnumSerializer.
 *
 * This is a generic serializer for any enum type used in IPDL.
 * Programmers can define ParamTraits<E> for enum type E by deriving
 * EnumSerializer<E, MyEnumValidator> where MyEnumValidator is a struct
 * that has to define a static IsLegalValue function returning whether
 * a given value is a legal value of the enum type at hand.
 *
 * \sa https://developer.mozilla.org/en/IPDL/Type_Serialization
 */
template <typename E, typename EnumValidator>
struct EnumSerializer {
  typedef E paramType;

  // XXX(Bug 1690343) Should this be changed to
  // std::make_unsigned_t<std::underlying_type_t<paramType>>, to make this more
  // consistent with the type used for validating values?
  typedef typename mozilla::UnsignedStdintTypeForSize<sizeof(paramType)>::Type
      uintParamType;

  static void Write(MessageWriter* aWriter, const paramType& aValue) {
    // XXX This assertion is somewhat meaningless at least for E that don't have
    // a fixed underlying type: if aValue weren't a legal value, we would
    // already have UB where this function is called.
    MOZ_RELEASE_ASSERT(EnumValidator::IsLegalValue(
        static_cast<std::underlying_type_t<paramType>>(aValue)));
    WriteParam(aWriter, uintParamType(aValue));
  }

  static bool Read(MessageReader* aReader, paramType* aResult) {
    uintParamType value;
    if (!ReadParam(aReader, &value)) {
      CrashReporter::AnnotateCrashReport(
          CrashReporter::Annotation::IPCReadErrorReason, "Bad iter"_ns);
      return false;
    } else if (!EnumValidator::IsLegalValue(value)) {
      CrashReporter::AnnotateCrashReport(
          CrashReporter::Annotation::IPCReadErrorReason, "Illegal value"_ns);
      return false;
    }
    *aResult = paramType(value);
    return true;
  }
};

template <typename E, E MinLegal, E HighBound>
class ContiguousEnumValidator {
  // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8:
  // "comparison of unsigned expression >= 0 is always true"
  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856
  template <typename T>
  static bool IsLessThanOrEqual(T a, T b) {
    return a <= b;
  }

 public:
  using IntegralType = std::underlying_type_t<E>;
  static constexpr auto kMinLegalIntegral = static_cast<IntegralType>(MinLegal);
  static constexpr auto kHighBoundIntegral =
      static_cast<IntegralType>(HighBound);

  static bool IsLegalValue(const IntegralType e) {
    return IsLessThanOrEqual(kMinLegalIntegral, e) && e < kHighBoundIntegral;
  }
};

template <typename E, E MinLegal, E MaxLegal>
class ContiguousEnumValidatorInclusive {
  // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8:
  // "comparison of unsigned expression >= 0 is always true"
  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856
  template <typename T>
  static bool IsLessThanOrEqual(T a, T b) {
    return a <= b;
  }

 public:
  using IntegralType = std::underlying_type_t<E>;
  static constexpr auto kMinLegalIntegral = static_cast<IntegralType>(MinLegal);
  static constexpr auto kMaxLegalIntegral = static_cast<IntegralType>(MaxLegal);

  static bool IsLegalValue(const IntegralType e) {
    return IsLessThanOrEqual(kMinLegalIntegral, e) && e <= kMaxLegalIntegral;
  }
};

template <typename E, E AllBits>
struct BitFlagsEnumValidator {
  static bool IsLegalValue(const std::underlying_type_t<E> e) {
    return (e & static_cast<std::underlying_type_t<E>>(AllBits)) == e;
  }
};

/**
 * Specialization of EnumSerializer for enums with contiguous enum values.
 *
 * Provide two values: MinLegal, HighBound. An enum value x will be
 * considered legal if MinLegal <= x < HighBound.
 *
 * For example, following is definition of serializer for enum type FOO.
 * \code
 * enum FOO { FOO_FIRST, FOO_SECOND, FOO_LAST, NUM_FOO };
 *
 * template <>
 * struct ParamTraits<FOO>:
 *     public ContiguousEnumSerializer<FOO, FOO_FIRST, NUM_FOO> {};
 * \endcode
 * FOO_FIRST, FOO_SECOND, and FOO_LAST are valid value.
 */
template <typename E, E MinLegal, E HighBound>
struct ContiguousEnumSerializer
    : EnumSerializer<E, ContiguousEnumValidator<E, MinLegal, HighBound>> {};

/**
 * This is similar to ContiguousEnumSerializer, but the last template
 * parameter is expected to be the highest legal value, rather than a
 * sentinel value. This is intended to support enumerations that don't
 * have sentinel values.
 */
template <typename E, E MinLegal, E MaxLegal>
struct ContiguousEnumSerializerInclusive
    : EnumSerializer<E,
                     ContiguousEnumValidatorInclusive<E, MinLegal, MaxLegal>> {
};

/**
 * Specialization of EnumSerializer for enums representing bit flags.
 *
 * Provide one value: AllBits. An enum value x will be
 * considered legal if (x & AllBits) == x;
 *
 * Example:
 * \code
 * enum FOO {
 *   FOO_FIRST =  1 << 0,
 *   FOO_SECOND = 1 << 1,
 *   FOO_LAST =   1 << 2,
 *   ALL_BITS =   (1 << 3) - 1
 * };
 *
 * template <>
 * struct ParamTraits<FOO>:
 *     public BitFlagsEnumSerializer<FOO, FOO::ALL_BITS> {};
 * \endcode
 */
template <typename E, E AllBits>
struct BitFlagsEnumSerializer
    : EnumSerializer<E, BitFlagsEnumValidator<E, AllBits>> {};

} /* namespace IPC */

#endif /* __IPC_GLUE_ENUMSERIALIZER_H__ */