// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_WIN_VARIANT_UTIL_H_ #define BASE_WIN_VARIANT_UTIL_H_ #include "base/logging.h" namespace base { namespace win { namespace internal { // Returns true if a VARIANT of type |self| can be assigned to a // variant of type |other|. // Does not allow converting unsigned <-> signed or converting between // different sized types, but does allow converting IDispatch* -> IUnknown*. constexpr bool VarTypeIsConvertibleTo(VARTYPE self, VARTYPE other) { // IDispatch inherits from IUnknown, so it's safe to // upcast a VT_DISPATCH into an IUnknown*. return (self == other) || (self == VT_DISPATCH && other == VT_UNKNOWN); } // VartypeToNativeType contains the underlying |Type| and offset to the // VARIANT union member related to the |ElementVartype| for simple types. template struct VartypeToNativeType final {}; template <> struct VartypeToNativeType final { using Type = VARIANT_BOOL; static constexpr VARIANT_BOOL VARIANT::*kMemberOffset = &VARIANT::boolVal; }; template <> struct VartypeToNativeType final { using Type = int8_t; static constexpr CHAR VARIANT::*kMemberOffset = &VARIANT::cVal; }; template <> struct VartypeToNativeType final { using Type = uint8_t; static constexpr BYTE VARIANT::*kMemberOffset = &VARIANT::bVal; }; template <> struct VartypeToNativeType final { using Type = int16_t; static constexpr SHORT VARIANT::*kMemberOffset = &VARIANT::iVal; }; template <> struct VartypeToNativeType final { using Type = uint16_t; static constexpr USHORT VARIANT::*kMemberOffset = &VARIANT::uiVal; }; template <> struct VartypeToNativeType final { using Type = int32_t; static constexpr LONG VARIANT::*kMemberOffset = &VARIANT::lVal; }; template <> struct VartypeToNativeType final { using Type = uint32_t; static constexpr ULONG VARIANT::*kMemberOffset = &VARIANT::ulVal; }; template <> struct VartypeToNativeType final { using Type = int64_t; static constexpr LONGLONG VARIANT::*kMemberOffset = &VARIANT::llVal; }; template <> struct VartypeToNativeType final { using Type = uint64_t; static constexpr ULONGLONG VARIANT::*kMemberOffset = &VARIANT::ullVal; }; template <> struct VartypeToNativeType final { using Type = float; static constexpr FLOAT VARIANT::*kMemberOffset = &VARIANT::fltVal; }; template <> struct VartypeToNativeType final { using Type = double; static constexpr DOUBLE VARIANT::*kMemberOffset = &VARIANT::dblVal; }; template <> struct VartypeToNativeType final { using Type = DATE; static constexpr DATE VARIANT::*kMemberOffset = &VARIANT::date; }; template <> struct VartypeToNativeType final { using Type = BSTR; static constexpr BSTR VARIANT::*kMemberOffset = &VARIANT::bstrVal; }; template <> struct VartypeToNativeType final { using Type = IUnknown*; static constexpr IUnknown* VARIANT::*kMemberOffset = &VARIANT::punkVal; }; template <> struct VartypeToNativeType final { using Type = IDispatch*; static constexpr IDispatch* VARIANT::*kMemberOffset = &VARIANT::pdispVal; }; // VariantUtil contains the underlying |Type| and helper methods // related to the |ElementVartype| for simple types. template struct VariantUtil final { using Type = typename VartypeToNativeType::Type; static constexpr bool IsConvertibleTo(VARTYPE vartype) { return VarTypeIsConvertibleTo(ElementVartype, vartype); } static constexpr bool IsConvertibleFrom(VARTYPE vartype) { return VarTypeIsConvertibleTo(vartype, ElementVartype); } // Get the associated VARIANT union member value. // Returns the value owned by the VARIANT without affecting the lifetime // of managed contents. // e.g. Does not affect IUnknown* reference counts or allocate a BSTR. static Type RawGet(const VARIANT& var) { DCHECK(IsConvertibleFrom(V_VT(&var))); return var.*VartypeToNativeType::kMemberOffset; } // Set the associated VARIANT union member value. // The caller is responsible for handling the lifetime of managed contents. // e.g. Incrementing IUnknown* reference counts or allocating a BSTR. static void RawSet(VARIANT* var, Type value) { DCHECK(IsConvertibleTo(V_VT(var))); var->*VartypeToNativeType::kMemberOffset = value; } }; } // namespace internal } // namespace win } // namespace base #endif // BASE_WIN_VARIANT_UTIL_H_