// Filename: dcast.h
// Created by:  drose (06Aug01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#ifndef DCAST_H
#define DCAST_H

#include "pandabase.h"

#include "typeHandle.h"
#include "typedObject.h"

// The DCAST (downcast) macro is defined as a convenience for
// downcasting from some TypedObject pointer (or a PointerTo).  It's
// just a normal C++-style downcast, except it first checks get_type()
// to make sure the downcasting is safe.  If you compile with NDEBUG,
// or set verify-dcast to #f, this check is removed.

// DCAST will return NULL if the downcasting is unsafe.  If you'd
// rather it abort out of the function (a la nassertv/nassertr), then
// see DCAST_INTO_V and DCAST_INTO_R, below.

template<class WantType>
INLINE WantType *_dcast(WantType *, TypedObject *ptr);
template<class WantType>
INLINE const WantType *_dcast(WantType *, const TypedObject *ptr);

// Note: it is important that DCAST not repeat the pointer parameter,
// since many users of DCAST may want to use the result of a function
// as the pointer parameter, and it could be terribly confusing and
// difficult to trace if the function were inadvertently executed
// twice.  This happened!
#define DCAST(want_type, pointer) _dcast((want_type*)0, pointer)

// DCAST_INTO_V and DCAST_INTO_R are similar in purpose to DCAST,
// except they: (a) automatically assign a variable instead of
// returning the downcasted pointer, and (b) they immediately return
// out of the function if the downcasting fails.  DCAST_INTO_V is for
// use in a void function and returns nothing; DCAST_INTO_R is for use
// in a non-void function and returns the indicated value.

// Both DCAST_INTO_V and DCAST_INTO_R accept as the first parameter a
// variable of type (want_type *) or (const want_type *), instead of
// the name of the type.  This variable will be filled with the new
// pointer.


// _dcast_ref is used to implement DCAST_INTO_V and DCAST_INTO_R.  Its
// difference from _dcast is that it takes a reference to a pointer as
// a first parameter.  The main point of this is to shut up the
// compiler about pointers used before their value is assigned.
template<class WantType>
INLINE WantType *_dcast_ref(WantType *&, TypedObject *ptr);
template<class WantType>
INLINE const WantType *_dcast_ref(WantType *&, const TypedObject *ptr);

#ifndef NDEBUG
// _dcast_verify performs the actual verification.
EXPCL_PANDAEXPRESS bool
_dcast_verify(TypeHandle want_handle, size_t want_size, 
              const TypedObject *ptr);
#endif  // NDEBUG

#define DCAST_INTO_V(to_pointer, from_pointer) \
  { \
    (to_pointer) = _dcast_ref(to_pointer, from_pointer); \
    nassertv((void *)(to_pointer) != (void *)NULL); \
  }

#define DCAST_INTO_R(to_pointer, from_pointer, return_value) \
  { \
    (to_pointer) = _dcast_ref(to_pointer, from_pointer); \
    nassertr((void *)(to_pointer) != (void *)NULL, return_value); \
  }

#include "dcast.T"

#endif
