2 /// Expose C++ objects to Nasal as ghosts
4 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Library General Public
8 // License as published by the Free Software Foundation; either
9 // version 2 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Library General Public License for more details.
16 // You should have received a copy of the GNU Library General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #ifndef SG_NASAL_GHOST_HXX_
21 #define SG_NASAL_GHOST_HXX_
23 #include "NasalCallContext.hxx"
24 #include "NasalObjectHolder.hxx"
26 #include <simgear/debug/logstream.hxx>
27 #include <simgear/structure/SGWeakReferenced.hxx>
28 #include <simgear/structure/SGWeakPtr.hxx>
30 #include <boost/bind.hpp>
31 #include <boost/call_traits.hpp>
32 #include <boost/function.hpp>
33 #include <boost/lambda/lambda.hpp>
34 #include <boost/mpl/has_xxx.hpp>
35 #include <boost/preprocessor/iteration/iterate.hpp>
36 #include <boost/shared_ptr.hpp>
37 #include <boost/utility/enable_if.hpp>
42 inline T* get_pointer(boost::weak_ptr<T> const& p)
44 return p.lock().get();
48 inline T* get_pointer(SGWeakPtr<T> const& p)
50 return p.lock().get();
56 inline T* get_pointer(observer_ptr<T> const& p)
65 inline typename boost::enable_if<
74 // Both ways of retrieving the address of a static member function
75 // should be legal but not all compilers know this.
76 // g++-4.4.7+ has been tested to work with both versions
77 #if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407
78 // The old version of g++ used on Jenkins (16.11.2012) only compiles
80 # define SG_GET_TEMPLATE_MEMBER(type, member) &member
82 // With old g++ on Jenkins (21.07.2014), ADL for boost::static_pointer_cast
84 using boost::static_pointer_cast;
86 // VS (2008, 2010, ... ?) only allow this version.
87 # define SG_GET_TEMPLATE_MEMBER(type, member) &type::template member
91 * Bindings between C++ and the Nasal scripting language
98 * Metadata for Ghost object types
103 typedef void(*Deleter)(void*);
104 typedef std::vector<std::pair<Deleter, void*> > DestroyList;
106 static DestroyList _destroy_list;
109 * Add a nasal base class to the ghost. Will be available in the ghosts
112 void addNasalBase(const naRef& parent);
114 bool isInstance(naGhostType* ghost_type, bool& is_weak) const;
118 const std::string _name_strong,
120 const naGhostType *_ghost_type_strong_ptr,
121 *_ghost_type_weak_ptr;
122 std::vector<naRef> _parents;
124 GhostMetadata( const std::string& name,
125 const naGhostType* ghost_type_strong,
126 const naGhostType* ghost_type_weak );
128 void addDerived(const GhostMetadata* derived);
130 naRef getParents(naContext c);
134 * Hold callable method and convert to Nasal function if required.
137 public SGWeakReferenced
140 virtual ~MethodHolder() {}
142 naRef get_naRef(naContext c)
145 _obj.reset(createNasalObject(c));
146 return _obj.get_naRef();
152 virtual naRef createNasalObject(naContext c) = 0;
155 BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
160 typedef typename boost::remove_cv<
161 typename boost::remove_reference<T>::type
165 template<class T1, class T2>
166 struct reduced_is_same:
167 public boost::is_same<typename reduced_type<T1>::type, T2>
171 /** @brief Destroy all ghost queued for deletion.
173 * This needs can not be done directly during garbage collection, as
174 * destructors may execute Nasal code which requires creating new Nasal
175 * contexts. Creating a Nasal context during garbage collection is not
176 * possible and leads to a dead lock.
178 void ghostProcessDestroyList();
180 typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
181 typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
183 // Dummy template to create shorter and easy to understand compile errors if
184 // trying to wrap the wrong type as a Ghost.
185 template<class T, class Enable = void>
189 BOOST_STATIC_ASSERT(("Ghost can only wrap shared pointer!"
190 && is_strong_ref<T>::value
193 static Ghost& init(const std::string& name);
194 static bool isInit();
198 * Class for exposing C++ objects to Nasal
201 * // Example class to be exposed to Nasal
209 * void doSomethingElse(const nasal::CallContext& ctx);
211 * typedef boost::shared_ptr<MyClass> MyClassPtr;
213 * std::string myOtherFreeMember(int num);
215 * void exposeClasses()
217 * // Register a nasal ghost type for MyClass. This needs to be done only
218 * // once before creating the first ghost instance. The exposed class needs
219 * // to be wrapped inside a shared pointer, eg. boost::shared_ptr.
220 * Ghost<MyClassPtr>::init("MyClass")
221 * // Members can be exposed by getters and setters
222 * .member("x", &MyClass::getX, &MyClass::setX)
223 * // For readonly variables only pass a getter
224 * .member("x_readonly", &MyClass::getX)
225 * // It is also possible to expose writeonly members
226 * .member("x_writeonly", &MyClass::setX)
227 * // Methods can be nearly anything callable and accepting a reference
228 * // to an instance of the class type. (member functions, free functions
229 * // and anything else bindable using boost::function and boost::bind)
230 * .method("myMember", &MyClass::myMember)
231 * .method("doSomething", &MyClass::doSomethingElse)
232 * .method("other", &myOtherFreeMember);
237 class Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>:
238 public internal::GhostMetadata
240 // Shared pointer required for Ghost (no weak pointer!)
241 BOOST_STATIC_ASSERT((is_strong_ref<T>::value));
244 typedef typename T::element_type raw_type;
245 typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
246 typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
247 typedef naRef (raw_type::*member_func_t)(const CallContext&);
248 typedef naRef (*free_func_t)(raw_type&, const CallContext&);
249 typedef boost::function<naRef(raw_type&, naContext)> getter_t;
250 typedef boost::function<void( raw_type&, naContext, naRef)> setter_t;
251 typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
252 typedef boost::function<bool( raw_type&,
255 naRef& )> fallback_getter_t;
256 typedef boost::function<bool( raw_type&,
259 naRef )> fallback_setter_t;
262 public internal::MethodHolder
265 explicit MethodHolder(const method_t& method):
271 typedef SGSharedPtr<MethodHolder> SharedPtr;
272 typedef SGWeakPtr<MethodHolder> WeakPtr;
276 virtual naRef createNasalObject(naContext c)
288 static void destroyHolder(void* user_data)
290 delete static_cast<WeakPtr*>(user_data);
293 static naRef call( naContext c,
299 WeakPtr* holder_weak = static_cast<WeakPtr*>(user_data);
301 naRuntimeError(c, "invalid method holder!");
305 SharedPtr holder = holder_weak->lock();
307 throw std::runtime_error("holder has expired");
309 // Keep reference for duration of call to prevent expiring
310 // TODO not needed for strong referenced ghost
311 strong_ref ref = fromNasal(c, me);
314 naGhostType* ghost_type = naGhost_type(me);
318 "method called on object of wrong type: "
319 "is '%s' expected '%s'",
321 : (ghost_type ? ghost_type->name : "unknown"),
322 _ghost_type_strong.name
326 return holder->_method
329 CallContext(c, me, argc, args)
332 catch(const std::exception& ex)
334 naRuntimeError(c, "Fatal error in method call: %s", ex.what());
338 naRuntimeError(c, "Unknown exception in method call.");
346 * A ghost member. Can consist either of getter and/or setter functions
347 * for exposing a data variable or a single callable function.
354 member_t( const getter_t& getter,
355 const setter_t& setter,
356 const MethodHolderPtr& func = MethodHolderPtr() ):
362 explicit member_t(const MethodHolderPtr& func):
368 MethodHolderPtr func;
371 typedef std::map<std::string, member_t> MemberMap;
374 * Register a new ghost type.
376 * @note Only intialize each ghost type once!
378 * @param name Descriptive name of the ghost type.
380 static Ghost& init(const std::string& name)
382 getSingletonHolder().reset( new Ghost(name) );
383 return *getSingletonPtr();
387 * Check whether ghost type has already been initialized.
391 return getSingletonPtr();
395 * Register a base class for this ghost. The base class needs to be
396 * registers on its own before it can be used as base class.
398 * @tparam BaseGhost Type of base class already wrapped into Ghost class
402 * Ghost<MyBasePtr>::init("MyBase");
403 * Ghost<MyClassPtr>::init("MyClass")
404 * .bases<Ghost<MyBasePtr> >();
407 template<class BaseGhost>
408 typename boost::enable_if
410 boost::is_base_of<GhostMetadata, BaseGhost>,
417 boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
420 typedef typename BaseGhost::strong_ref base_ref;
422 BaseGhost* base = BaseGhost::getSingletonPtr();
425 SG_GET_TEMPLATE_MEMBER(Ghost, toNasal<BaseGhost>),
426 SG_GET_TEMPLATE_MEMBER(Ghost, fromNasalWithCast<base_ref>)
429 // Replace any getter that is not available in the current class.
430 // TODO check if this is the correct behavior of function overriding
431 for( typename BaseGhost::MemberMap::const_iterator member =
432 base->_members.begin();
433 member != base->_members.end();
436 if( _members.find(member->first) == _members.end() )
437 _members[member->first] = member_t
439 member->second.getter,
440 member->second.setter,
445 if( !_fallback_setter )
446 _fallback_setter = base->_fallback_setter;
447 if( !_fallback_getter )
448 _fallback_getter = base->_fallback_getter;
454 * Register a base class for this ghost. The base class needs to be
455 * registers on its own before it can be used as base class.
457 * @tparam Base Type of base class (Base as used in Ghost<BasePtr>)
460 * Ghost<MyBasePtr>::init("MyBase");
461 * Ghost<MyClassPtr>::init("MyClass")
462 * .bases<MyBasePtr>();
466 typename boost::disable_if
468 boost::is_base_of<GhostMetadata, Base>,
475 boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
478 return bases< Ghost<Base> >();
482 * Register an existing Nasal class/hash as base class for this ghost.
484 * @param parent Nasal hash/class
486 Ghost& bases(const naRef& parent)
488 addNasalBase(parent);
493 * Register a member variable by passing a getter and/or setter method.
495 * @param field Name of member
496 * @param getter Getter for variable
497 * @param setter Setter for variable (Pass 0 to prevent write access)
500 template<class Ret, class Param>
501 Ghost& member( const std::string& field,
502 Ret (raw_type::*getter)() const,
503 void (raw_type::*setter)(Param) )
505 return member(field, to_getter(getter), to_setter(setter));
508 template<class Param>
509 Ghost& member( const std::string& field,
510 const getter_t& getter,
511 void (raw_type::*setter)(Param) )
513 return member(field, getter, to_setter(setter));
517 Ghost& member( const std::string& field,
518 Ret (raw_type::*getter)() const,
519 const setter_t& setter )
521 return member(field, to_getter(getter), setter);
525 * Register a read only member variable.
527 * @param field Name of member
528 * @param getter Getter for variable
531 Ghost& member( const std::string& field,
532 Ret (raw_type::*getter)() const )
534 return member(field, to_getter(getter), setter_t());
537 Ghost& member( const std::string& field,
538 naRef (*getter)(const raw_type&, naContext) )
540 return member(field, getter_t(getter), setter_t());
543 Ghost& member( const std::string& field,
544 naRef (*getter)(raw_type&, naContext) )
546 return member(field, getter_t(getter), setter_t());
550 * Register a write only member variable.
552 * @param field Name of member
553 * @param setter Setter for variable
556 Ghost& member( const std::string& field,
557 void (raw_type::*setter)(Var) )
559 return member(field, getter_t(), to_setter(setter));
562 Ghost& member( const std::string& field,
563 void (*setter)(raw_type&, naContext, naRef) )
565 return member(field, getter_t(), setter_t(setter));
568 Ghost& member( const std::string& field,
569 const setter_t& setter )
571 return member(field, getter_t(), setter);
575 * Register a member variable by passing a getter and/or setter method.
577 * @param field Name of member
578 * @param getter Getter for variable
579 * @param setter Setter for variable (Pass empty to prevent write access)
582 Ghost& member( const std::string& field,
583 const getter_t& getter,
584 const setter_t& setter = setter_t() )
586 if( !getter.empty() || !setter.empty() )
587 _members[field] = member_t(getter, setter);
593 "Member '" << field << "' requires a getter or setter"
599 * Register a function which is called upon retrieving an unknown member
602 Ghost& _get(const fallback_getter_t& getter)
604 _fallback_getter = getter;
609 * Register a function which is called upon retrieving an unknown member
610 * of this ghost, and convert it to the given @a Param type.
612 template<class Param>
613 Ghost& _get( const boost::function<bool ( raw_type&,
617 return _get(boost::bind(
618 convert_param_invoker<Param>, getter, _1, _2, _3, _4
623 * Register a method which is called upon retrieving an unknown member of
630 * bool getMember( const std::string& key,
631 * std::string& value_out ) const;
634 * Ghost<MyClassPtr>::init("Test")
635 * ._get(&MyClass::getMember);
638 template<class Param>
639 Ghost& _get(bool (raw_type::*getter)(const std::string&, Param&) const)
642 boost::function<bool (raw_type&, const std::string&, Param&)>(getter)
647 * Register a method which is called upon retrieving an unknown member of
654 * bool getMember( naContext c,
655 * const std::string& key,
656 * naRef& value_out );
659 * Ghost<MyClassPtr>::init("Test")
660 * ._get(&MyClass::getMember);
663 Ghost& _get(bool (raw_type::*getter)( naContext,
667 return _get( fallback_getter_t(getter) );
671 * Register a function which is called upon setting an unknown member of
674 Ghost& _set(const fallback_setter_t& setter)
676 _fallback_setter = setter;
681 * Register a function which is called upon setting an unknown member of
682 * this ghost, and convert it to the given @a Param type.
684 template<class Param>
685 Ghost& _set(const boost::function<bool ( raw_type&,
689 // Setter signature: bool( raw_type&,
691 // const std::string&,
693 return _set(boost::bind(
697 boost::bind(from_nasal_ptr<Param>::get(), _2, _4)
702 * Register a method which is called upon setting an unknown member of
709 * bool setMember( const std::string& key,
710 * const std::string& value );
713 * Ghost<MyClassPtr>::init("Test")
714 * ._set(&MyClass::setMember);
717 template<class Param>
718 Ghost& _set(bool (raw_type::*setter)(const std::string&, Param))
721 boost::function<bool (raw_type&, const std::string&, Param)>(setter)
726 * Register a method which is called upon setting an unknown member of
733 * bool setMember( naContext c,
734 * const std::string& key,
738 * Ghost<MyClassPtr>::init("Test")
739 * ._set(&MyClass::setMember);
742 Ghost& _set(bool (raw_type::*setter)( naContext,
746 return _set( fallback_setter_t(setter) );
750 * Register anything that accepts an object instance and a
751 * nasal::CallContext and returns naRef as method.
757 * naRef myMethod(const nasal::CallContext& ctx);
760 * Ghost<MyClassPtr>::init("Test")
761 * .method("myMethod", &MyClass::myMethod);
764 Ghost& method(const std::string& name, const method_t& func)
766 _members[name].func = new MethodHolder(func);
771 * Register anything that accepts an object instance and a
772 * nasal::CallContext whith automatic conversion of the return type to
777 * void doIt(const MyClass& c, const nasal::CallContext& ctx);
779 * Ghost<MyClassPtr>::init("Test")
780 * .method("doIt", &doIt);
786 const std::string& name,
787 const boost::function<Ret (raw_type&, const CallContext&)>& func
790 return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
793 // Build dependency for CMake, gcc, etc.
794 #define SG_DONT_DO_ANYTHING
795 # include <simgear/nasal/cppbind/detail/functor_templates.hxx>
796 #undef SG_DONT_DO_ANYTHING
798 #define BOOST_PP_ITERATION_LIMITS (0, 9)
799 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
800 #include BOOST_PP_ITERATE()
803 * Create a shared pointer on the heap to handle the reference counting
804 * for the passed shared pointer while it is used in Nasal space.
806 template<class RefType>
808 typename boost::enable_if_c<
809 boost::is_same<RefType, strong_ref>::value
810 || boost::is_same<RefType, weak_ref>::value,
813 makeGhost(naContext c, RefType const& ref_ptr)
815 strong_ref ref(ref_ptr);
816 raw_type* ptr = get_pointer(ref);
820 // We are wrapping shared pointers to already existing objects which
821 // will then be hold be a new shared pointer. We therefore have to
822 // check for the dynamic type of the object as it might differ from
823 // the passed static type.
824 return toNasal<Ghost>(
827 shared_ptr_traits<RefType>::is_strong::value
832 * Convert Nasal object to C++ object. To get a valid object the passed
833 * Nasal objects has to be derived class of the target class (Either
834 * derived in C++ or in Nasal using a 'parents' vector)
836 static strong_ref fromNasal(naContext c, naRef me)
838 naGhostType* ghost_type = naGhost_type(me);
841 // Check if we got an instance of this class
842 bool is_weak = false;
843 if( isInstance(ghost_type, is_weak) )
845 return is_weak ? getPtr<strong_ref, true>(naGhost_ptr(me))
846 : getPtr<strong_ref, false>(naGhost_ptr(me));
849 // otherwise try the derived classes
850 for( typename DerivedList::reverse_iterator
851 derived = getSingletonPtr()->_derived_types.rbegin();
852 derived != getSingletonPtr()->_derived_types.rend();
855 strong_ref ref = (derived->from_nasal)(c, me);
857 if( get_pointer(ref) )
861 else if( naIsHash(me) )
863 naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
864 if( !naIsVector(na_parents) )
867 typedef std::vector<naRef> naRefs;
868 naRefs parents = from_nasal<naRefs>(c, na_parents);
869 for( naRefs::const_iterator parent = parents.begin();
870 parent != parents.end();
873 strong_ref ref = fromNasal(c, *parent);
874 if( get_pointer(ref) )
884 template<class, class>
887 static naGhostType _ghost_type_strong, //!< Stored as shared pointer
888 _ghost_type_weak; //!< Stored as weak shared pointer
890 typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool);
891 typedef strong_ref (*from_nasal_t)(naContext, naRef);
895 from_nasal_t from_nasal;
897 DerivedInfo( to_nasal_t to_nasal_func,
898 from_nasal_t from_nasal_func ):
899 to_nasal(to_nasal_func),
900 from_nasal(from_nasal_func)
904 typedef std::vector<DerivedInfo> DerivedList;
905 DerivedList _derived_types;
907 static bool isInstance(naGhostType* ghost_type, bool& is_weak)
909 if( !ghost_type || !getSingletonPtr() )
912 return getSingletonPtr()->GhostMetadata::isInstance( ghost_type,
916 template<class RefPtr, bool is_weak>
918 typename boost::enable_if_c<
924 typedef shared_ptr_storage<strong_ref> storage_type;
926 return storage_type::template get<RefPtr>(
927 static_cast<typename storage_type::storage_type*>(ptr)
933 template<class RefPtr, bool is_weak>
935 typename boost::enable_if_c<
936 is_weak && supports_weak_ref<T>::value,
941 typedef shared_ptr_storage<weak_ref> storage_type;
943 return storage_type::template get<RefPtr>(
944 static_cast<typename storage_type::storage_type*>(ptr)
950 template<class RefPtr, bool is_weak>
952 typename boost::enable_if_c<
953 is_weak && !supports_weak_ref<T>::value,
961 void addDerived( const internal::GhostMetadata* derived_meta,
962 to_nasal_t to_nasal_func,
963 from_nasal_t from_nasal_func )
965 GhostMetadata::addDerived(derived_meta);
966 _derived_types.push_back(DerivedInfo(to_nasal_func, from_nasal_func));
969 template<class BaseGhost>
971 typename boost::enable_if
972 < boost::is_polymorphic<typename BaseGhost::raw_type>,
975 toNasal( naContext c,
976 const typename BaseGhost::strong_ref& base_ref,
979 typename BaseGhost::raw_type* ptr = get_pointer(base_ref);
981 // Check first if passed pointer can by converted to instance of class
984 < typename BaseGhost::raw_type,
985 typename Ghost::raw_type
987 && dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
990 if( !getSingletonPtr() )
996 "Ghost::getTypeFor: can not get type for unregistered ghost"
1002 static_pointer_cast<typename Ghost::raw_type>(base_ref);
1004 // Now check if we can further downcast to one of our derived classes.
1005 for( typename DerivedList::reverse_iterator
1006 derived = getSingletonPtr()->_derived_types.rbegin();
1007 derived != getSingletonPtr()->_derived_types.rend();
1010 naRef ghost = (derived->to_nasal)(c, ref, strong);
1012 if( !naIsNil(ghost) )
1016 // If base is not an instance of any derived class, this class has to
1017 // be the dynamic type.
1019 ? create<false>(c, ref)
1020 : create<true>(c, ref);
1023 template<class BaseGhost>
1025 typename boost::disable_if
1026 < boost::is_polymorphic<typename BaseGhost::raw_type>,
1029 toNasal( naContext c,
1030 const typename BaseGhost::strong_ref& ref,
1033 // For non polymorphic classes there is no possibility to get the actual
1034 // dynamic type, therefore we can only use its static type.
1036 ? create<false>(c, ref)
1037 : create<true>(c, ref);
1040 template<class Type>
1041 static Type fromNasalWithCast(naContext c, naRef me)
1043 return Type(fromNasal(c, me));
1046 static Ghost* getSingletonPtr()
1048 return getSingletonHolder().get();
1052 getter_t to_getter(Ret (raw_type::*getter)() const)
1054 typedef typename boost::call_traits<Ret>::param_type param_type;
1055 naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
1057 // Getter signature: naRef(raw_type&, naContext)
1062 boost::bind(getter, _1)
1066 template<class Param>
1067 setter_t to_setter(void (raw_type::*setter)(Param))
1069 // Setter signature: void(raw_type&, naContext, naRef)
1074 boost::bind(from_nasal_ptr<Param>::get(), _2, _3)
1079 * Invoke a method which writes the converted parameter to a reference
1081 template<class Param>
1083 bool convert_param_invoker
1085 const boost::function<bool ( raw_type&,
1090 const std::string& key,
1095 if( !func(obj, key, p) )
1098 out = to_nasal(c, p);
1103 * Invoke a method which returns a value and convert it to Nasal.
1107 typename boost::disable_if<boost::is_void<Ret>, naRef>::type
1110 const boost::function<Ret (raw_type&, const CallContext&)>& func,
1112 const CallContext& ctx
1115 return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
1119 * Invoke a method which returns void and "convert" it to nil.
1123 typename boost::enable_if<boost::is_void<Ret>, naRef>::type
1126 const boost::function<Ret (raw_type&, const CallContext&)>& func,
1128 const CallContext& ctx
1136 * Extract argument by index from nasal::CallContext and convert to given
1141 typename boost::disable_if<
1142 internal::reduced_is_same<Arg, CallContext>,
1143 typename from_nasal_ptr<Arg>::return_type
1145 arg_from_nasal(const CallContext& ctx, size_t index)
1147 return ctx.requireArg<Arg>(index);
1151 * Specialization to pass through nasal::CallContext.
1155 typename boost::enable_if<
1156 internal::reduced_is_same<Arg, CallContext>,
1157 typename from_nasal_ptr<Arg>::return_type
1159 arg_from_nasal(const CallContext& ctx, size_t)
1161 // Either const CallContext& or CallContext, non-const reference
1162 // does not make sense.
1163 BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
1167 typedef std::auto_ptr<Ghost> GhostPtr;
1169 fallback_getter_t _fallback_getter;
1170 fallback_setter_t _fallback_setter;
1172 explicit Ghost(const std::string& name):
1173 GhostMetadata( name,
1174 &_ghost_type_strong,
1175 supports_weak_ref<T>::value ? &_ghost_type_weak : NULL )
1177 _ghost_type_strong.destroy =
1178 SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<strong_ref>);
1179 _ghost_type_strong.name = _name_strong.c_str();
1180 _ghost_type_strong.get_member = &Ghost::getMemberStrong;
1181 _ghost_type_strong.set_member = &Ghost::setMemberStrong;
1183 _ghost_type_weak.destroy =
1184 SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<weak_ref>);
1185 _ghost_type_weak.name = _name_weak.c_str();
1187 if( supports_weak_ref<T>::value )
1189 _ghost_type_weak.get_member = &Ghost::getMemberWeak;
1190 _ghost_type_weak.set_member = &Ghost::setMemberWeak;
1194 _ghost_type_weak.get_member = 0;
1195 _ghost_type_weak.set_member = 0;
1199 static GhostPtr& getSingletonHolder()
1201 static GhostPtr instance;
1205 template<bool is_weak>
1207 typename boost::enable_if_c<
1211 create(naContext c, const strong_ref& ref_ptr)
1213 typedef shared_ptr_storage<strong_ref> storage_type;
1214 return naNewGhost2( c,
1215 &Ghost::_ghost_type_strong,
1216 storage_type::ref(ref_ptr) );
1219 template<bool is_weak>
1221 typename boost::enable_if_c<
1222 is_weak && supports_weak_ref<T>::value,
1225 create(naContext c, const strong_ref& ref_ptr)
1227 typedef shared_ptr_storage<weak_ref> storage_type;
1228 return naNewGhost2( c,
1229 &Ghost::_ghost_type_weak,
1230 storage_type::ref(ref_ptr) );
1233 template<bool is_weak>
1235 typename boost::enable_if_c<
1236 is_weak && !supports_weak_ref<T>::value,
1239 create(naContext, const strong_ref&)
1244 template<class Type>
1245 static void destroy(void *ptr)
1247 typedef shared_ptr_storage<Type> storage_type;
1248 storage_type::unref(
1249 static_cast<typename storage_type::storage_type*>(ptr)
1253 template<class Type>
1254 static void queueDestroy(void *ptr)
1256 _destroy_list.push_back( DestroyList::value_type(&destroy<Type>, ptr) );
1259 static void raiseErrorExpired(naContext c, const char* str)
1261 Ghost* ghost_info = getSingletonPtr();
1264 "Ghost::%s: ghost has expired '%s'",
1266 ghost_info ? ghost_info->_name_strong.c_str() : "unknown"
1271 * Callback for retrieving a ghost member.
1273 static const char* getMemberImpl( naContext c,
1278 const std::string key_str = nasal::from_nasal<std::string>(c, key);
1279 // TODO merge instance parents with static class parents
1280 // if( key_str == "parents" )
1282 // if( getSingletonPtr()->_parents.empty() )
1285 // *out = getSingletonPtr()->getParents(c);
1289 typename MemberMap::iterator member =
1290 getSingletonPtr()->_members.find(key_str);
1292 if( member == getSingletonPtr()->_members.end() )
1294 fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
1296 || !fallback_get(obj, c, key_str, *out) )
1299 else if( member->second.func )
1300 *out = member->second.func->get_naRef(c);
1301 else if( !member->second.getter.empty() )
1302 *out = member->second.getter(obj, c);
1304 return "Read-protected member";
1310 getMemberWeak(naContext c, void* ghost, naRef key, naRef* out)
1312 // Keep a strong reference while retrieving member, to prevent deleting
1313 // object in between.
1314 strong_ref ref = getPtr<strong_ref, true>(ghost);
1316 raiseErrorExpired(c, "getMember");
1318 return getMemberImpl(c, *get_pointer(ref), key, out);
1322 getMemberStrong(naContext c, void* ghost, naRef key, naRef* out)
1324 // Just get a raw pointer as we are keeping a strong reference as ghost
1326 raw_type* ptr = getPtr<raw_type*, false>(ghost);
1327 return getMemberImpl(c, *ptr, key, out);
1331 * Callback for writing to a ghost member.
1333 static void setMemberImpl( naContext c,
1338 const std::string key = nasal::from_nasal<std::string>(c, field);
1339 const MemberMap& members = getSingletonPtr()->_members;
1341 typename MemberMap::const_iterator member = members.find(key);
1342 if( member == members.end() )
1344 fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
1346 naRuntimeError(c, "ghost: No such member: %s", key.c_str());
1347 else if( !fallback_set(obj, c, key, val) )
1348 naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
1350 else if( member->second.setter.empty() )
1351 naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
1352 else if( member->second.func )
1353 naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
1355 member->second.setter(obj, c, val);
1359 setMemberWeak(naContext c, void* ghost, naRef field, naRef val)
1361 // Keep a strong reference while retrieving member, to prevent deleting
1362 // object in between.
1363 strong_ref ref = getPtr<strong_ref, true>(ghost);
1365 raiseErrorExpired(c, "setMember");
1367 setMemberImpl(c, *get_pointer(ref), field, val);
1371 setMemberStrong(naContext c, void* ghost, naRef field, naRef val)
1373 // Just get a raw pointer as we are keeping a strong reference as ghost
1375 raw_type* ptr = getPtr<raw_type*, false>(ghost);
1376 setMemberImpl(c, *ptr, field, val);
1382 Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
1383 ::_ghost_type_strong;
1387 Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
1390 } // namespace nasal
1392 // Needs to be outside any namespace to make ADL work
1394 * Convert every shared pointer to a ghost.
1397 typename boost::enable_if<
1398 nasal::internal::has_element_type<
1399 typename nasal::internal::reduced_type<T>::type
1403 to_nasal_helper(naContext c, T ptr)
1405 typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
1406 return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
1410 * Convert nasal ghosts/hashes to shared pointer (of a ghost).
1413 typename boost::enable_if<
1414 nasal::internal::has_element_type<
1415 typename nasal::internal::reduced_type<T>::type
1419 from_nasal_helper(naContext c, naRef ref, const T*)
1421 typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
1422 return T(nasal::Ghost<strong_ref>::fromNasal(c, ref));
1426 * Convert any pointer to a SGReferenced based object to a ghost.
1429 typename boost::enable_if_c<
1430 boost::is_base_of<SGReferenced, T>::value
1431 || boost::is_base_of<SGWeakReferenced, T>::value,
1434 to_nasal_helper(naContext c, T* ptr)
1436 return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
1440 * Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
1443 typename boost::enable_if_c<
1446 typename boost::remove_pointer<T>::type
1448 || boost::is_base_of<
1450 typename boost::remove_pointer<T>::type
1454 from_nasal_helper(naContext c, naRef ref, const T*)
1456 typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
1457 return T(nasal::Ghost<TypeRef>::fromNasal(c, ref));
1461 * Convert any pointer to a osg::Referenced based object to a ghost.
1464 typename boost::enable_if<
1465 boost::is_base_of<osg::Referenced, T>,
1468 to_nasal_helper(naContext c, T* ptr)
1470 return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<T>(ptr));
1474 * Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
1477 typename boost::enable_if<
1478 boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
1481 from_nasal_helper(naContext c, naRef ref, const T*)
1483 typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
1484 return T(nasal::Ghost<TypeRef>::fromNasal(c, ref));
1487 #endif /* SG_NASAL_GHOST_HXX_ */