// To generate typewrapping.h from typewrapping.h.pump, execute:
// /home/build/google3/third_party/gtest/scripts/pump.py typewrapping.h.pump

// Copyright 2009 Google Inc.
// Author: tschmelcher@google.com (Tristan Schmelcher)
//
// A template meta-programming framework for customizable rule-based
// type-checking of type wrappers and wrapper functions.
//
// This framework is useful in a scenario where there are a set of types that
// you choose to "wrap" by implementing new preferred types such that the new
// and the old can be converted back and forth in some way, but you already have
// a library of functions that expect the original types. Example:
//
// Type A wraps X
// Type B wraps Y
// Type C wraps Z
//
// And function X Foo(Y, Z) exists.
//
// Since A, B, and C are preferred, you choose to implement a wrapper function
// with this interface:
//
// A Foo2(B, C)
//
// However, this can lead to subtle discrepancies, because if the interface to
// Foo ever changes then Foo2 may become out-of-sync. e.g., Foo might have
// originally returned void, but later is changed to return an error code. If
// the programmer forgets to change Foo2, the code will probably still work, but
// with an implicit cast to void inserted by the compiler, potentially leading
// to run-time errors or errors in usage.
//
// The purpose of this library is to prevent these discrepancies from occurring.
// You use it as follows:
//
// First, declare a new wrapping ruleset:
//
// DECLARE_WRAPPING_RULESET(ruleset_name)
//
// Then declare rules on what types wrap which other types and how to convert
// them:
//
// DECLARE_WRAPPER(ruleset_name, A, X, variable_name, wrapping_code,
//     unwrapping_code)
//
// Where wrapping_code and unwrapping_code are expressions giving the code to
// use to wrap and unwrap a variable with the name "variable_name". There are
// also some helper macros to declare common wrapping schemes.
//
// Then implement your wrapped functions like this:
//
// A Foo_Wrapped(B b, C c) {
//   return WRAP_CALL2(ruleset_name, A, Foo, B, b, C, c);
// }
//
// WRAP_CALL2 will unwrap b and c (if B and C are wrapped types) and call Foo,
// then wrap the result to type A if different from the return type. More
// importantly, if the types in Foo's interface do not _exactly_ match the
// unwrapped forms of A, B, and C (after typedef-equivalence), then you will get
// a compile-time error for a static_cast from the real function type to the
// expected one (except on Mac where this check is infeasible), and with no icky
// template instantiation errors either!
//
// There are also macros to wrap/unwrap individual values according to whichever
// rule applies to their types:
//
// WRAP(ruleset_name, A, X, value) // Compile-time error if no associated rule.
//
// UNWRAP(ruleset_name, A, value) // Infers X. If A is not a wrapper, no change.
//
// UNWRAP_TYPE(ruleset_name, A) // Evaluates to X.
//
//
// Essentially, the library works by "storing" the DECLARE_WRAPPER calls in
// template specializations. When the wrapper or unwrapper is invoked, the
// normal C++ template system essentially "looks up" the rule for the given
// type(s).
//
// All of the auto-generated code can be inlined to produce zero impact on
// run-time performance and code size (though some compilers may require
// gentle encouragement in order for them to do so).

#ifndef TALK_SESSION_PHONE_TYPEWRAPPING_H_
#define TALK_SESSION_PHONE_TYPEWRAPPING_H_

#include "talk/base/common.h"

#ifdef OSX
// XCode's GCC doesn't respect typedef-equivalence when casting function pointer
// types, so we can't enforce that the wrapped function signatures strictly
// match the expected types. Instead we have to forego the nice user-friendly
// static_cast check (because it will spuriously fail) and make the Call()
// function into a member template below.
#define CAST_FUNCTION_(function, ...) \
  function
#else
#define CAST_FUNCTION_(function, ...) \
  static_cast<__VA_ARGS__>(function)
#endif

// Internal helper macros.
#define SMART_WRAPPER_(wrapper, toType, fromType, from) \
  (wrapper<toType, fromType>::Wrap(from))

#define SMART_UNWRAPPER_(unwrapper, fromType, from) \
  (unwrapper<fromType>::Unwrap(from))

#define SMART_UNWRAPPER_TYPE_(unwrapper, fromType) \
  typename unwrapper<fromType>::ToType

$var n = 27
$range i 0..n

$for i [[
$range j 1..i

// The code that follows wraps calls to $i-argument functions, unwrapping the
// arguments and wrapping the return value as needed.

// The usual case.
template<
    template <typename ToType, typename FromType> class Wrapper,
    template <typename FromType> class Unwrapper,
    typename ReturnType$for j [[,
    typename ArgType$j]]>
class SmartFunctionWrapper$i {
 public:
  typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ReturnType) OriginalReturnType;

$for j [[
  typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ArgType$j) OriginalArgType$j;

]]
  typedef OriginalReturnType (*OriginalFunctionType)($for j , [[

      OriginalArgType$j]]);

#ifdef OSX
  template <typename F>
  static FORCE_INLINE ReturnType Call(F function
#else
  static FORCE_INLINE ReturnType Call(OriginalFunctionType function
#endif
                                      $for j [[,
                                      ArgType$j v$j]]) {
    return SMART_WRAPPER_(Wrapper, ReturnType, OriginalReturnType,
        (*function)($for j , [[

            SMART_UNWRAPPER_(Unwrapper, ArgType$j, v$j)]]));
  }
};

// Special case for functions that return void. (SMART_WRAPPER_ involves
// passing the unwrapped value in a function call, which is not a legal thing to
// do with void, so we need a special case here that doesn't call
// SMART_WRAPPER_()).
template<
    template <typename ToType, typename FromType> class Wrapper,
    template <typename FromType> class Unwrapper$for j [[,
    typename ArgType$j]]>
class SmartFunctionWrapper$i<
    Wrapper,
    Unwrapper,
    void$for j [[,
    ArgType$j]]> {
 public:
  typedef void OriginalReturnType;

$for j [[
  typedef SMART_UNWRAPPER_TYPE_(Unwrapper, ArgType$j) OriginalArgType$j;

]]
  typedef OriginalReturnType (*OriginalFunctionType)($for j , [[

      OriginalArgType$j]]);

#ifdef OSX
  template <typename F>
  static FORCE_INLINE void Call(F function
#else
  static FORCE_INLINE void Call(OriginalFunctionType function
#endif
                                $for j [[,
                                ArgType$j v$j]]) {
    (*function)($for j , [[

        SMART_UNWRAPPER_(Unwrapper, ArgType$j, v$j)]]);
  }
};


]]
// Programmer interface follows. Only macros below here should be used outside
// this file.

#define DECLARE_WRAPPING_RULESET(ruleSet) \
  namespace ruleSet { \
\
  /* SmartWrapper is for wrapping values. */ \
  template<typename ToType, typename FromType> \
  class SmartWrapper; \
\
  /* Special case where the types are the same. */ \
  template<typename T1> \
  class SmartWrapper<T1, T1> { \
   public: \
    static FORCE_INLINE T1 Wrap(T1 from) { \
      return from; \
    } \
  }; \
\
  /* Class for unwrapping (i.e., going to the original value). This is done
     function-style rather than predicate-style. The default rule is to leave
     the type unchanged. */ \
  template<typename FromType> \
  class SmartUnwrapper { \
   public: \
    typedef FromType ToType; \
    static FORCE_INLINE ToType Unwrap(FromType from) { \
      return from; \
    } \
  }; \
\
  }

// Declares a wrapping rule.
#define DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, var, wrapCode, unwrapCode) \
  namespace ruleSet { \
\
  template<> \
  class SmartWrapper<wrappedType, unwrappedType> { \
   public: \
    static FORCE_INLINE wrappedType Wrap(unwrappedType var) { \
      return wrapCode; \
    } \
  }; \
\
  template<> \
  class SmartUnwrapper<wrappedType> { \
   public: \
    typedef unwrappedType ToType; \
    static FORCE_INLINE unwrappedType Unwrap(wrappedType var) { \
      return unwrapCode; \
    } \
  }; \
\
  }

// Helper macro for declaring a wrapper that wraps/unwraps with reinterpret_cast<>.
#define DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType, unwrappedType) \
  DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, FROM, reinterpret_cast<wrappedType>(FROM), reinterpret_cast<unwrappedType>(FROM))

// Helper macro for declaring a wrapper that wraps/unwraps implicitly.
#define DECLARE_WRAPPER_BY_IMPLICIT_CAST(ruleSet, wrappedType, unwrappedType) \
  DECLARE_WRAPPER(ruleSet, wrappedType, unwrappedType, FROM, FROM, FROM)

// Helper macro for declaring that the pointer types for one type wrap the pointer types for another type.
#define DECLARE_POINTER_WRAPPER(ruleSet, wrappedType, unwrappedType) \
  DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType*, unwrappedType*) \
  DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, const wrappedType*, const unwrappedType*) \
  DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, wrappedType* const, unwrappedType* const) \
  DECLARE_WRAPPER_BY_REINTERPRET_CAST(ruleSet, const wrappedType* const, const unwrappedType* const) \

// Macro to wrap a single value.
#define WRAP(ruleSet, toType, fromType, from) \
  SMART_WRAPPER_(ruleSet::SmartWrapper, toType, fromType, from)

// Macro to unwrap a single value.
#define UNWRAP(ruleSet, fromType, from) \
  SMART_UNWRAPPER_(ruleSet::SmartUnwrapper, fromType, from)

// Macro to get the unwrapped form of a type.
#define UNWRAP_TYPE(ruleSet, fromType) \
  SMART_UNWRAPPER_TYPE_(ruleSet::SmartUnwrapper, from)

// Macros to wrap function calls.

$for i [[
$range j 1..i
#define WRAP_CALL$i(ruleSet, toType, function$for j [[, argType$j, arg$j]]) \
  (SmartFunctionWrapper$i< \
      ruleSet::SmartWrapper, \
      ruleSet::SmartUnwrapper, \
      toType$for j [[, \
      argType$j]]>::Call( \
          CAST_FUNCTION_( \
              &function, \
              SmartFunctionWrapper$i< \
                  ruleSet::SmartWrapper, \
                  ruleSet::SmartUnwrapper, \
                  toType$for j [[, \
                  argType$j]]>::OriginalFunctionType)$for j [[, \
          arg$j]]))

]]

#endif  // TALK_SESSION_PHONE_TYPEWRAPPINGHELPERS_H_
