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
18namespace mojo {
19namespace internal {
20
21template <typename T>
22struct 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
33template <
34    typename Traits,
35    typename UserType,
36    typename std::enable_if<HasIsNullMethod<Traits>::value>::type* = nullptr>
37bool CallIsNullIfExists(const UserType& input) {
38  return Traits::IsNull(input);
39}
40
41template <
42    typename Traits,
43    typename UserType,
44    typename std::enable_if<!HasIsNullMethod<Traits>::value>::type* = nullptr>
45bool CallIsNullIfExists(const UserType& input) {
46  return false;
47}
48template <typename T>
49struct 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
60template <
61    typename Traits,
62    typename UserType,
63    typename std::enable_if<HasSetToNullMethod<Traits>::value>::type* = nullptr>
64bool CallSetToNullIfExists(UserType* output) {
65  Traits::SetToNull(output);
66  return true;
67}
68
69template <typename Traits,
70          typename UserType,
71          typename std::enable_if<!HasSetToNullMethod<Traits>::value>::type* =
72              nullptr>
73bool 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
80template <typename T>
81struct 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
92template <typename Traits,
93          bool has_context = HasSetUpContextMethod<Traits>::value>
94struct CustomContextHelper;
95
96template <typename Traits>
97struct 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
119template <typename Traits>
120struct 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
134template <typename ReturnType, typename ParamType, typename InputUserType>
135ReturnType CallWithContext(ReturnType (*f)(ParamType, void*),
136                           InputUserType&& input,
137                           void* context) {
138  return f(std::forward<InputUserType>(input), context);
139}
140
141template <typename ReturnType, typename ParamType, typename InputUserType>
142ReturnType CallWithContext(ReturnType (*f)(ParamType),
143                           InputUserType&& input,
144                           void* context) {
145  return f(std::forward<InputUserType>(input));
146}
147
148template <typename T, typename MaybeConstUserType>
149struct 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
160template <
161    typename Traits,
162    typename MaybeConstUserType,
163    typename std::enable_if<
164        HasGetBeginMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
165decltype(Traits::GetBegin(std::declval<MaybeConstUserType&>()))
166CallGetBeginIfExists(MaybeConstUserType& input) {
167  return Traits::GetBegin(input);
168}
169
170template <
171    typename Traits,
172    typename MaybeConstUserType,
173    typename std::enable_if<
174        !HasGetBeginMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
175size_t CallGetBeginIfExists(MaybeConstUserType& input) {
176  return 0;
177}
178
179template <typename T, typename MaybeConstUserType>
180struct 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
191template <
192    typename Traits,
193    typename MaybeConstUserType,
194    typename std::enable_if<
195        HasGetDataMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
196decltype(Traits::GetData(std::declval<MaybeConstUserType&>()))
197CallGetDataIfExists(MaybeConstUserType& input) {
198  return Traits::GetData(input);
199}
200
201template <
202    typename Traits,
203    typename MaybeConstUserType,
204    typename std::enable_if<
205        !HasGetDataMethod<Traits, MaybeConstUserType>::value>::type* = nullptr>
206void* 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