910e62b5创建于 1月15日历史提交
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_

#include <type_traits>

#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
#include "mojo/public/cpp/bindings/lib/template_util.h"

namespace mojo {
namespace internal {

template <typename T, typename U, typename SFINAE = void>
struct HasIsNullMethod : std::false_type {
  static_assert(sizeof(T), "T must be a complete type.");
};

template <typename T, typename U>
struct HasIsNullMethod<
    T,
    U,
    std::void_t<decltype(T::IsNull(std::declval<const U&>()))>>
    : std::true_type {};

template <typename Traits, typename UserType>
bool CallIsNullIfExists(const UserType& input) {
  if constexpr (HasIsNullMethod<Traits, UserType>::value) {
    return Traits::IsNull(input);
  } else {
    return false;
  }
}

template <typename T, typename U, typename SFINAE = void>
struct HasSetToNullMethod : std::false_type {
  static_assert(sizeof(T), "T must be a complete type.");
};

template <typename T, typename U>
struct HasSetToNullMethod<
    T,
    U,
    std::void_t<decltype(T::SetToNull(std::declval<U*>()))>> : std::true_type {
};

template <typename Traits, typename UserType>
bool CallSetToNullIfExists(UserType* output) {
  if constexpr (HasSetToNullMethod<Traits, UserType>::value) {
    Traits::SetToNull(output);
  }

  // Note that it is not considered an error to attempt to read a null value
  // into a non-nullable `output` object. In such cases, the caller must have
  // used a DataView's corresponding MaybeRead[FieldName] method, thus
  // explicitly choosing to ignore null values without affecting `output`.
  //
  // If instead a caller unwittingly attempts to use a corresponding
  // Read[FieldName] method to read an optional value into the same non-nullable
  // UserType, it will result in a compile-time error. As such, we don't need to
  // account for that case here.
  return true;
}

template <typename MojomType, typename UserType, typename = void>
struct TraitsFinder {
  using Traits = StructTraits<MojomType, UserType>;
};

template <typename MojomType, typename UserType>
struct TraitsFinder<
    MojomType,
    UserType,
    std::enable_if_t<BelongsTo<MojomType, MojomTypeCategory::kUnion>::value>> {
  using Traits = UnionTraits<MojomType, UserType>;
};

template <typename UserType>
struct TraitsFinder<StringDataView, UserType> {
  using Traits = StringTraits<UserType>;
};

template <typename UserType, typename ElementType>
struct TraitsFinder<ArrayDataView<ElementType>, UserType> {
  using Traits = ArrayTraits<UserType>;
};

template <typename UserType, typename KeyType, typename ValueType>
struct TraitsFinder<MapDataView<KeyType, ValueType>, UserType> {
  using Traits = MapTraits<UserType>;
};

template <typename MojomType, typename UserType>
constexpr bool IsValidUserTypeForOptionalValue() {
  if constexpr (IsStdOptional<UserType>::value) {
    return true;
  } else {
    using Traits = typename TraitsFinder<MojomType, UserType>::Traits;
    return HasSetToNullMethod<Traits, UserType>::value;
  }
}

template <typename T, typename U, typename SFINAE = void>
struct HasGetBeginMethod : std::false_type {
  static_assert(sizeof(T), "T must be a complete type.");
};

template <typename T, typename U>
struct HasGetBeginMethod<T,
                         U,
                         std::void_t<decltype(T::GetBegin(std::declval<U&>()))>>
    : std::true_type {};

template <typename T, typename U, typename SFINAE = void>
struct HasGetDataMethod : std::false_type {
  static_assert(sizeof(T), "T must be a complete type.");
};

// TODO(dcheng): Figure out why the `&` below is load-bearing and document it or
// improve this and remove the hack.
template <typename T, typename U>
struct HasGetDataMethod<T,
                        U,
                        std::void_t<decltype(&T::GetData(std::declval<U&>()))>>
    : std::true_type {};

}  // namespace internal
}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_UTIL_H_