// Copyright David Abrahams 2002.

// Distributed under the Boost Software License, Version 1.0. (See

// accompanying file LICENSE_1_0.txt or copy at

// http://www.boost.org/LICENSE_1_0.txt)

#ifndef OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP

# define OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP



# include <boost/python/detail/prefix.hpp>

# include <boost/python/detail/referent_storage.hpp>

# include <boost/python/detail/destroy.hpp>

# include <boost/python/detail/construct.hpp>

# include <boost/python/converter/object_manager.hpp>

# include <boost/python/detail/raw_pyobject.hpp>

# include <boost/python/tag.hpp>



//

// arg_from_python converters for Python type wrappers, to be used as

// base classes for specializations.

//

namespace boost { namespace python { namespace converter { 



template <class T>

struct object_manager_value_arg_from_python

{

    typedef T result_type;

    

    object_manager_value_arg_from_python(PyObject*);

    bool convertible() const;

    T operator()() const;

 private:

    PyObject* m_source;

};



// Used for converting reference-to-object-manager arguments from

// python. The process used here is a little bit odd. Upon

// construction, we build the object manager object in the m_result

// object, *forcing* it to accept the source Python object by casting

// its pointer to detail::borrowed_reference. This is supposed to

// bypass any type checking of the source object. The convertible

// check then extracts the owned object and checks it. If the check

// fails, nothing else in the program ever gets to touch this strange

// "forced" object.

template <class Ref>

struct object_manager_ref_arg_from_python

{

    typedef Ref result_type;

    

    object_manager_ref_arg_from_python(PyObject*);

    bool convertible() const;

    Ref operator()() const;

    ~object_manager_ref_arg_from_python();

 private:

    typename python::detail::referent_storage<Ref>::type m_result;

};



//

// implementations

//



template <class T>

inline object_manager_value_arg_from_python<T>::object_manager_value_arg_from_python(PyObject* x)

    : m_source(x)

{

}

    

template <class T>

inline bool object_manager_value_arg_from_python<T>::convertible() const

{

    return object_manager_traits<T>::check(m_source);

}



template <class T>

inline T object_manager_value_arg_from_python<T>::operator()() const

{

    return T(python::detail::borrowed_reference(m_source));

}



template <class Ref>

inline object_manager_ref_arg_from_python<Ref>::object_manager_ref_arg_from_python(PyObject* x)

{

# if defined(__EDG_VERSION__) && __EDG_VERSION__ <= 243

    // needed for warning suppression

    python::detail::borrowed_reference x_ = python::detail::borrowed_reference(x);

    python::detail::construct_referent<Ref>(&m_result.bytes, x_);

# else 

    python::detail::construct_referent<Ref>(&m_result.bytes, (python::detail::borrowed_reference)x);

# endif 

}



template <class Ref>

inline object_manager_ref_arg_from_python<Ref>::~object_manager_ref_arg_from_python()

{

    python::detail::destroy_referent<Ref>(this->m_result.bytes);

}



namespace detail

{

  template <class T>

  inline bool object_manager_ref_check(T const& x)

  {

      return object_manager_traits<T>::check(get_managed_object(x, tag));

  }

}



template <class Ref>

inline bool object_manager_ref_arg_from_python<Ref>::convertible() const

{

    return detail::object_manager_ref_check(

        python::detail::void_ptr_to_reference(this->m_result.bytes, (Ref(*)())0));

}



template <class Ref>

inline Ref object_manager_ref_arg_from_python<Ref>::operator()() const

{

    return python::detail::void_ptr_to_reference(

        this->m_result.bytes, (Ref(*)())0);

}



}}} // namespace boost::python::converter



#endif // OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP

