1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <queue>
12 
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
16 #include "mojo/public/cpp/bindings/lib/serialization_context.h"
17 
18 namespace mojo {
19 namespace internal {
20 
21 template <typename T>
22 struct HasIsNullMethod {
23   template <typename U>
24   static char Test(decltype(U::IsNull)*);
25   template <typename U>
26   static int Test(...);
27   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
28 
29  private:
30   EnsureTypeIsComplete<T> check_t_;
31 };
32 
33 template <
34     typename Traits,
35     typename UserType,
36     typename std::enable_if<HasIsNullMethod<Traits>::value>::type* = nullptr>
CallIsNullIfExists(const UserType & input)37 bool CallIsNullIfExists(const UserType& input) {
38   return Traits::IsNull(input);
39 }
40 
41 template <
42     typename Traits,
43     typename UserType,
44     typename std::enable_if<!HasIsNullMethod<Traits>::value>::type* = nullptr>
CallIsNullIfExists(const UserType & input)45 bool CallIsNullIfExists(const UserType& input) {
46   return false;
47 }
48 template <typename T>
49 struct HasSetToNullMethod {
50   template <typename U>
51   static char Test(decltype(U::SetToNull)*);
52   template <typename U>
53   static int Test(...);
54   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
55 
56  private:
57   EnsureTypeIsComplete<T> check_t_;
58 };
59 
60 template <
61     typename Traits,
62     typename UserType,
63     typename std::enable_if<HasSetToNullMethod<Traits>::value>::type* = nullptr>
CallSetToNullIfExists(UserType * output)64 bool CallSetToNullIfExists(UserType* output) {
65   Traits::SetToNull(output);
66   return true;
67 }
68 
69 template <typename Traits,
70           typename UserType,
71           typename std::enable_if<!HasSetToNullMethod<Traits>::value>::type* =
72               nullptr>
CallSetToNullIfExists(UserType * output)73 bool CallSetToNullIfExists(UserType* output) {
74   LOG(ERROR) << "A null value is received. But the Struct/Array/StringTraits "
75              << "class doesn't define a SetToNull() function and therefore is "
76              << "unable to deserialize the value.";
77   return false;
78 }
79 
80 template <typename T>
81 struct HasSetUpContextMethod {
82   template <typename U>
83   static char Test(decltype(U::SetUpContext)*);
84   template <typename U>
85   static int Test(...);
86   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
87 
88  private:
89   EnsureTypeIsComplete<T> check_t_;
90 };
91 
92 template <typename Traits,
93           bool has_context = HasSetUpContextMethod<Traits>::value>
94 struct CustomContextHelper;
95 
96 template <typename Traits>
97 struct CustomContextHelper<Traits, true> {
98   template <typename MaybeConstUserType>
99   static void* SetUp(MaybeConstUserType& input, SerializationContext* context) {
100     void* custom_context = Traits::SetUpContext(input);
101     if (!context->custom_contexts)
102       context->custom_contexts.reset(new std::queue<void*>());
103     context->custom_contexts->push(custom_context);
104     return custom_context;
105   }
106 
107   static void* GetNext(SerializationContext* context) {
108     void* custom_context = context->custom_contexts->front();
109     context->custom_contexts->pop();
110     return custom_context;
111   }
112 
113   template <typename MaybeConstUserType>
114   static void TearDown(MaybeConstUserType& input, void* custom_context) {
115     Traits::TearDownContext(input, custom_context);
116   }
117 };
118 
119 template <typename Traits>
120 struct CustomContextHelper<Traits, false> {
121   template <typename MaybeConstUserType>
122   static void* SetUp(MaybeConstUserType& input, SerializationContext* context) {
123     return nullptr;
124   }
125 
126   static void* GetNext(SerializationContext* context) { return nullptr; }
127 
128   template <typename MaybeConstUserType>
129   static void TearDown(MaybeConstUserType& input, void* custom_context) {
130     DCHECK(!custom_context);
131   }
132 };
133 
134 template <typename ReturnType, typename ParamType, typename InputUserType>
135 ReturnType CallWithContext(ReturnType (*f)(ParamType, void*),
136                            InputUserType&& input,
137                            void* context) {
138   return f(std::forward<InputUserType>(input), context);
139 }
140 
141 template <typename ReturnType, typename ParamType, typename InputUserType>
142 ReturnType CallWithContext(ReturnType (*f)(ParamType),
143                            InputUserType&& input,
144                            void* context) {
145   return f(std::forward<InputUserType>(input));
146 }
147 
148 template <typename T, typename MaybeConstUserType>
149 struct HasGetBeginMethod {
150   template <typename U>
151   static char Test(decltype(U::GetBegin(std::declval<MaybeConstUserType&>()))*);
152   template <typename U>
153   static int Test(...);
154   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
155 
156  private:
157   EnsureTypeIsComplete<T> check_t_;
158 };
159 
160 template <
161     typename Traits,
162     typename MaybeConstUserType,
163     typename std::enable_if<
164         HasGetBeginMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
165 decltype(Traits::GetBegin(std::declval<MaybeConstUserType&>()))
166 CallGetBeginIfExists(MaybeConstUserType& input) {
167   return Traits::GetBegin(input);
168 }
169 
170 template <
171     typename Traits,
172     typename MaybeConstUserType,
173     typename std::enable_if<
174         !HasGetBeginMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
175 size_t CallGetBeginIfExists(MaybeConstUserType& input) {
176   return 0;
177 }
178 
179 template <typename T, typename MaybeConstUserType>
180 struct HasGetDataMethod {
181   template <typename U>
182   static char Test(decltype(U::GetData(std::declval<MaybeConstUserType&>()))*);
183   template <typename U>
184   static int Test(...);
185   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
186 
187  private:
188   EnsureTypeIsComplete<T> check_t_;
189 };
190 
191 template <
192     typename Traits,
193     typename MaybeConstUserType,
194     typename std::enable_if<
195         HasGetDataMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
196 decltype(Traits::GetData(std::declval<MaybeConstUserType&>()))
197 CallGetDataIfExists(MaybeConstUserType& input) {
198   return Traits::GetData(input);
199 }
200 
201 template <
202     typename Traits,
203     typename MaybeConstUserType,
204     typename std::enable_if<
205         !HasGetDataMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
206 void* CallGetDataIfExists(MaybeConstUserType& input) {
207   return nullptr;
208 }
209 
210 }  // namespace internal
211 }  // namespace mojo
212 
213 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_
214