]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/cppbind/Ghost.hxx
Fix for old versions of Boost.
[simgear.git] / simgear / nasal / cppbind / Ghost.hxx
1 ///@file
2 /// Expose C++ objects to Nasal as ghosts
3 ///
4 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
5 //
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.
10 //
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.
15 //
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
19
20 #ifndef SG_NASAL_GHOST_HXX_
21 #define SG_NASAL_GHOST_HXX_
22
23 #include "NasalCallContext.hxx"
24 #include "NasalObjectHolder.hxx"
25
26 #include <simgear/debug/logstream.hxx>
27 #include <simgear/structure/SGWeakReferenced.hxx>
28 #include <simgear/structure/SGWeakPtr.hxx>
29
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>
38
39 #include <map>
40
41 template<class T>
42 inline T* get_pointer(boost::weak_ptr<T> const& p)
43 {
44   return p.lock().get();
45 }
46
47 template<class T>
48 inline T* get_pointer(SGWeakPtr<T> const& p)
49 {
50   return p.lock().get();
51 }
52
53 template<class T>
54 inline T* get_pointer(osg::observer_ptr<T> const& p)
55 {
56   osg::ref_ptr<T> ref;
57   p.lock(ref);
58   return ref.get();
59 }
60
61 /**
62  * Bindings between C++ and the Nasal scripting language
63  */
64 namespace nasal
65 {
66   namespace internal
67   {
68     /**
69      * Metadata for Ghost object types
70      */
71     class GhostMetadata
72     {
73       public:
74         /**
75          * Add a nasal base class to the ghost. Will be available in the ghosts
76          * parents array.
77          */
78         void addNasalBase(const naRef& parent)
79         {
80           assert( naIsHash(parent) );
81           _parents.push_back(parent);
82         }
83
84         bool isBaseOf(naGhostType* ghost_type, bool& is_weak) const
85         {
86           if( ghost_type == _ghost_type_strong_ptr )
87           {
88             is_weak = false;
89             return true;
90           }
91
92           if( ghost_type == _ghost_type_weak_ptr )
93           {
94             is_weak = true;
95             return true;
96           }
97
98           for( DerivedList::const_iterator derived = _derived_classes.begin();
99                                            derived != _derived_classes.end();
100                                          ++derived )
101           {
102             if( (*derived)->isBaseOf(ghost_type, is_weak) )
103               return true;
104           }
105
106           return false;
107         }
108
109       protected:
110
111         typedef std::vector<const GhostMetadata*> DerivedList;
112
113         const std::string   _name_strong,
114                             _name_weak;
115         const naGhostType  *_ghost_type_strong_ptr,
116                            *_ghost_type_weak_ptr;
117         DerivedList         _derived_classes;
118         std::vector<naRef>  _parents;
119
120         GhostMetadata( const std::string& name,
121                        const naGhostType* ghost_type_strong,
122                        const naGhostType* ghost_type_weak ):
123           _name_strong(name),
124           _name_weak(name + " (weak ref)"),
125           _ghost_type_strong_ptr(ghost_type_strong),
126           _ghost_type_weak_ptr(ghost_type_weak)
127         {
128
129         }
130
131         void addDerived(const GhostMetadata* derived)
132         {
133           assert(derived);
134           _derived_classes.push_back(derived);
135
136           SG_LOG
137           (
138             SG_NASAL,
139             SG_INFO,
140             "Ghost::addDerived: " << _name_strong << " -> "
141                                   << derived->_name_strong
142           );
143         }
144
145         naRef getParents(naContext c)
146         {
147           return nasal::to_nasal(c, _parents);
148         }
149     };
150
151     /**
152      * Hold callable method and convert to Nasal function if required.
153      */
154     class MethodHolder:
155       public SGWeakReferenced
156     {
157       public:
158         virtual ~MethodHolder() {}
159
160         naRef get_naRef(naContext c)
161         {
162           if( !_obj.valid() )
163             _obj.reset(createNasalObject(c));
164           return _obj.get_naRef();
165         }
166
167       protected:
168         ObjectHolder<> _obj;
169
170         virtual naRef createNasalObject(naContext c) = 0;
171     };
172
173     BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
174
175     template<class T>
176     struct reduced_type
177     {
178       typedef typename boost::remove_cv<
179         typename boost::remove_reference<T>::type
180       >::type type;
181     };
182
183     template<class T1, class T2>
184     struct reduced_is_same:
185       public boost::is_same<typename reduced_type<T1>::type, T2>
186     {};
187   }
188
189   typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
190   typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
191
192   /**
193    * Class for exposing C++ objects to Nasal
194    *
195    * @code{cpp}
196    * // Example class to be exposed to Nasal
197    * class MyClass
198    * {
199    *   public:
200    *     void setX(int x);
201    *     int getX() const;
202    *
203    *     int myMember();
204    *     void doSomethingElse(const nasal::CallContext& ctx);
205    * }
206    * typedef boost::shared_ptr<MyClass> MyClassPtr;
207    *
208    * std::string myOtherFreeMember(int num);
209    *
210    * void exposeClasses()
211    * {
212    *   // Register a nasal ghost type for MyClass. This needs to be done only
213    *   // once before creating the first ghost instance. The exposed class needs
214    *   // to be wrapped inside a shared pointer, eg. boost::shared_ptr.
215    *   Ghost<MyClassPtr>::init("MyClass")
216    *     // Members can be exposed by getters and setters
217    *     .member("x", &MyClass::getX, &MyClass::setX)
218    *     // For readonly variables only pass a getter
219    *     .member("x_readonly", &MyClass::getX)
220    *     // It is also possible to expose writeonly members
221    *     .member("x_writeonly", &MyClass::setX)
222    *     // Methods can be nearly anything callable and accepting a reference
223    *     // to an instance of the class type. (member functions, free functions
224    *     // and anything else bindable using boost::function and boost::bind)
225    *     .method("myMember", &MyClass::myMember)
226    *     .method("doSomething", &MyClass::doSomethingElse)
227    *     .method("other", &myOtherFreeMember);
228    * }
229    * @endcode
230    */
231   template<class T>
232   class Ghost:
233     public internal::GhostMetadata
234   {
235       // Shared pointer required for Ghost (no weak pointer!)
236       BOOST_STATIC_ASSERT((shared_ptr_traits<T>::is_strong::value));
237
238     public:
239       typedef typename T::element_type                              raw_type;
240       typedef typename shared_ptr_traits<T>::strong_ref             strong_ref;
241       typedef typename shared_ptr_traits<T>::weak_ref               weak_ref;
242       typedef naRef (raw_type::*member_func_t)(const CallContext&);
243       typedef naRef (*free_func_t)(raw_type&, const CallContext&);
244       typedef boost::function<naRef(raw_type&, naContext)>          getter_t;
245       typedef boost::function<void( raw_type&, naContext, naRef)>   setter_t;
246       typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
247       typedef boost::function<bool( raw_type&,
248                                     naContext,
249                                     const std::string&,
250                                     naRef& )>              fallback_getter_t;
251       typedef boost::function<bool( raw_type&,
252                                     naContext,
253                                     const std::string&,
254                                     naRef )>               fallback_setter_t;
255
256       class MethodHolder:
257         public internal::MethodHolder
258       {
259         public:
260           explicit MethodHolder(const method_t& method):
261             _method(method)
262           {}
263
264         protected:
265
266           typedef SGSharedPtr<MethodHolder> SharedPtr;
267           typedef SGWeakPtr<MethodHolder> WeakPtr;
268
269           method_t  _method;
270
271           virtual naRef createNasalObject(naContext c)
272           {
273             return naNewFunc
274             (
275               c,
276               naNewCCodeUD( c,
277                             &MethodHolder::call,
278                             new WeakPtr(this),
279                             &destroyHolder )
280             );
281           }
282
283           static void destroyHolder(void* user_data)
284           {
285             delete static_cast<WeakPtr*>(user_data);
286           }
287
288           static naRef call( naContext c,
289                              naRef me,
290                              int argc,
291                              naRef* args,
292                              void* user_data )
293           {
294             WeakPtr* holder_weak = static_cast<WeakPtr*>(user_data);
295             if( !holder_weak )
296               naRuntimeError(c, "invalid method holder!");
297
298             try
299             {
300               SharedPtr holder = holder_weak->lock();
301               if( !holder )
302                 throw std::runtime_error("holder has expired");
303
304               return holder->_method
305               (
306                 requireObject(c, me),
307                 CallContext(c, argc, args)
308               );
309             }
310             catch(const std::exception& ex)
311             {
312               naRuntimeError(c, "Fatal error in method call: %s", ex.what());
313             }
314             catch(...)
315             {
316               naRuntimeError(c, "Unknown exception in method call.");
317             }
318
319             return naNil();
320           }
321       };
322
323       /**
324        * A ghost member. Can consist either of getter and/or setter functions
325        * for exposing a data variable or a single callable function.
326        */
327       struct member_t
328       {
329         member_t()
330         {}
331
332         member_t( const getter_t& getter,
333                   const setter_t& setter,
334                   const MethodHolderPtr& func = MethodHolderPtr() ):
335           getter( getter ),
336           setter( setter ),
337           func( func )
338         {}
339
340         explicit member_t(const MethodHolderPtr& func):
341           func( func )
342         {}
343
344         getter_t        getter;
345         setter_t        setter;
346         MethodHolderPtr func;
347       };
348
349       typedef std::map<std::string, member_t> MemberMap;
350
351       /**
352        * Register a new ghost type.
353        *
354        * @note Only intialize each ghost type once!
355        *
356        * @param name    Descriptive name of the ghost type.
357        */
358       static Ghost& init(const std::string& name)
359       {
360         getSingletonHolder().reset( new Ghost(name) );
361         return *getSingletonPtr();
362       }
363
364       /**
365        * Check whether ghost type has already been initialized.
366        */
367       static bool isInit()
368       {
369         return getSingletonPtr();
370       }
371
372       /**
373        * Register a base class for this ghost. The base class needs to be
374        * registers on its own before it can be used as base class.
375        *
376        * @tparam BaseGhost  Type of base class already wrapped into Ghost class
377        *                    (Ghost<BasePtr>)
378        *
379        * @code{cpp}
380        * Ghost<MyBasePtr>::init("MyBase");
381        * Ghost<MyClassPtr>::init("MyClass")
382        *   .bases<Ghost<MyBasePtr> >();
383        * @endcode
384        */
385       template<class BaseGhost>
386       typename boost::enable_if
387         <
388           boost::is_base_of<GhostMetadata, BaseGhost>,
389           Ghost
390         >::type&
391       bases()
392       {
393         BOOST_STATIC_ASSERT
394         ((
395           boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
396         ));
397
398         BaseGhost* base = BaseGhost::getSingletonPtr();
399         base->addDerived
400         (
401           this,
402           // Both ways of retrieving the address of a static member function
403           // should be legal but not all compilers know this.
404           // g++-4.4.7+ has been tested to work with both versions
405 #if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407
406           // The old version of g++ used on Jenkins (16.11.2012) only compiles
407           // this version.
408           &getTypeFor<BaseGhost>
409 #else
410           // VS (2008, 2010, ... ?) only allow this version.
411           &Ghost::getTypeFor<BaseGhost>
412 #endif
413         );
414
415         // Replace any getter that is not available in the current class.
416         // TODO check if this is the correct behavior of function overriding
417         for( typename BaseGhost::MemberMap::const_iterator member =
418                base->_members.begin();
419                member != base->_members.end();
420              ++member )
421         {
422           if( _members.find(member->first) == _members.end() )
423             _members[member->first] = member_t
424             (
425               member->second.getter,
426               member->second.setter,
427               member->second.func
428             );
429         }
430
431         if( !_fallback_setter )
432           _fallback_setter = base->_fallback_setter;
433         if( !_fallback_getter )
434           _fallback_getter = base->_fallback_getter;
435
436         return *this;
437       }
438
439       /**
440        * Register a base class for this ghost. The base class needs to be
441        * registers on its own before it can be used as base class.
442        *
443        * @tparam Base   Type of base class (Base as used in Ghost<BasePtr>)
444        *
445        * @code{cpp}
446        * Ghost<MyBasePtr>::init("MyBase");
447        * Ghost<MyClassPtr>::init("MyClass")
448        *   .bases<MyBasePtr>();
449        * @endcode
450        */
451       template<class Base>
452       typename boost::disable_if
453         <
454           boost::is_base_of<GhostMetadata, Base>,
455           Ghost
456         >::type&
457       bases()
458       {
459         BOOST_STATIC_ASSERT
460         ((
461           boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
462         ));
463
464         return bases< Ghost<Base> >();
465       }
466
467       /**
468        * Register an existing Nasal class/hash as base class for this ghost.
469        *
470        * @param parent  Nasal hash/class
471        */
472       Ghost& bases(const naRef& parent)
473       {
474         addNasalBase(parent);
475         return *this;
476       }
477
478       /**
479        * Register a member variable by passing a getter and/or setter method.
480        *
481        * @param field   Name of member
482        * @param getter  Getter for variable
483        * @param setter  Setter for variable (Pass 0 to prevent write access)
484        *
485        */
486       template<class Ret, class Param>
487       Ghost& member( const std::string& field,
488                      Ret (raw_type::*getter)() const,
489                      void (raw_type::*setter)(Param) )
490       {
491         return member(field, to_getter(getter), to_setter(setter));
492       }
493
494       template<class Param>
495       Ghost& member( const std::string& field,
496                      const getter_t& getter,
497                      void (raw_type::*setter)(Param) )
498       {
499         return member(field, getter, to_setter(setter));
500       }
501
502       template<class Ret>
503       Ghost& member( const std::string& field,
504                      Ret (raw_type::*getter)() const,
505                      const setter_t& setter )
506       {
507         return member(field, to_getter(getter), setter);
508       }
509
510       /**
511        * Register a read only member variable.
512        *
513        * @param field   Name of member
514        * @param getter  Getter for variable
515        */
516       template<class Ret>
517       Ghost& member( const std::string& field,
518                      Ret (raw_type::*getter)() const )
519       {
520         return member(field, to_getter(getter), setter_t());
521       }
522
523       Ghost& member( const std::string& field,
524                      naRef (*getter)(const raw_type&, naContext) )
525       {
526         return member(field, getter_t(getter), setter_t());
527       }
528
529       Ghost& member( const std::string& field,
530                      naRef (*getter)(raw_type&, naContext) )
531       {
532         return member(field, getter_t(getter), setter_t());
533       }
534
535       /**
536        * Register a write only member variable.
537        *
538        * @param field   Name of member
539        * @param setter  Setter for variable
540        */
541       template<class Var>
542       Ghost& member( const std::string& field,
543                      void (raw_type::*setter)(Var) )
544       {
545         return member(field, getter_t(), to_setter(setter));
546       }
547
548       Ghost& member( const std::string& field,
549                      void (*setter)(raw_type&, naContext, naRef) )
550       {
551         return member(field, getter_t(), setter_t(setter));
552       }
553
554       Ghost& member( const std::string& field,
555                      const setter_t& setter )
556       {
557         return member(field, getter_t(), setter);
558       }
559
560       /**
561        * Register a member variable by passing a getter and/or setter method.
562        *
563        * @param field   Name of member
564        * @param getter  Getter for variable
565        * @param setter  Setter for variable (Pass empty to prevent write access)
566        *
567        */
568       Ghost& member( const std::string& field,
569                      const getter_t& getter,
570                      const setter_t& setter = setter_t() )
571       {
572         if( !getter.empty() || !setter.empty() )
573           _members[field] = member_t(getter, setter);
574         else
575           SG_LOG
576           (
577             SG_NASAL,
578             SG_WARN,
579             "Member '" << field << "' requires a getter or setter"
580           );
581         return *this;
582       }
583
584       /**
585        * Register a function which is called upon retrieving an unknown member
586        * of this ghost.
587        */
588       Ghost& _get(const fallback_getter_t& getter)
589       {
590         _fallback_getter = getter;
591         return *this;
592       }
593
594       /**
595        * Register a function which is called upon retrieving an unknown member
596        * of this ghost, and convert it to the given @a Param type.
597        */
598       template<class Param>
599       Ghost& _get( const boost::function<bool ( raw_type&,
600                                                 const std::string&,
601                                                 Param& )>& getter )
602       {
603         return _get(boost::bind(
604           convert_param_invoker<Param>, getter, _1, _2, _3, _4
605         ));
606       }
607
608       /**
609        * Register a method which is called upon retrieving an unknown member of
610        * this ghost.
611        *
612        * @code{cpp}
613        * class MyClass
614        * {
615        *   public:
616        *     bool getMember( const std::string& key,
617        *                     std::string& value_out ) const;
618        * }
619        *
620        * Ghost<MyClassPtr>::init("Test")
621        *   ._get(&MyClass::getMember);
622        * @endcode
623        */
624       template<class Param>
625       Ghost& _get(bool (raw_type::*getter)(const std::string&, Param&) const)
626       {
627         return _get(
628           boost::function<bool (raw_type&, const std::string&, Param&)>(getter)
629         );
630       }
631
632       /**
633        * Register a method which is called upon retrieving an unknown member of
634        * this ghost.
635        *
636        * @code{cpp}
637        * class MyClass
638        * {
639        *   public:
640        *     bool getMember( naContext c,
641        *                     const std::string& key,
642        *                     naRef& value_out );
643        * }
644        *
645        * Ghost<MyClassPtr>::init("Test")
646        *   ._get(&MyClass::getMember);
647        * @endcode
648        */
649       Ghost& _get(bool (raw_type::*getter)( naContext,
650                                             const std::string&,
651                                             naRef& ) const)
652       {
653         return _get( fallback_getter_t(getter) );
654       }
655
656       /**
657        * Register a function which is called upon setting an unknown member of
658        * this ghost.
659        */
660       Ghost& _set(const fallback_setter_t& setter)
661       {
662         _fallback_setter = setter;
663         return *this;
664       }
665
666       /**
667        * Register a function which is called upon setting an unknown member of
668        * this ghost, and convert it to the given @a Param type.
669        */
670       template<class Param>
671       Ghost& _set(const boost::function<bool ( raw_type&,
672                                                const std::string&,
673                                                Param )>& setter)
674       {
675         // Setter signature: bool( raw_type&,
676         //                         naContext,
677         //                         const std::string&,
678         //                         naRef )
679         return _set(boost::bind(
680           setter,
681           _1,
682           _3,
683           boost::bind(from_nasal_ptr<Param>::get(), _2, _4)
684         ));
685       }
686
687       /**
688        * Register a method which is called upon setting an unknown member of
689        * this ghost.
690        *
691        * @code{cpp}
692        * class MyClass
693        * {
694        *   public:
695        *     bool setMember( const std::string& key,
696        *                     const std::string& value );
697        * }
698        *
699        * Ghost<MyClassPtr>::init("Test")
700        *   ._set(&MyClass::setMember);
701        * @endcode
702        */
703       template<class Param>
704       Ghost& _set(bool (raw_type::*setter)(const std::string&, Param))
705       {
706         return _set(
707           boost::function<bool (raw_type&, const std::string&, Param)>(setter)
708         );
709       }
710
711       /**
712        * Register a method which is called upon setting an unknown member of
713        * this ghost.
714        *
715        * @code{cpp}
716        * class MyClass
717        * {
718        *   public:
719        *     bool setMember( naContext c,
720        *                     const std::string& key,
721        *                     naRef value );
722        * }
723        *
724        * Ghost<MyClassPtr>::init("Test")
725        *   ._set(&MyClass::setMember);
726        * @endcode
727        */
728       Ghost& _set(bool (raw_type::*setter)( naContext,
729                                             const std::string&,
730                                             naRef ))
731       {
732         return _set( fallback_setter_t(setter) );
733       }
734
735       /**
736        * Register anything that accepts an object instance and a
737        * nasal::CallContext and returns naRef as method.
738        *
739        * @code{cpp}
740        * class MyClass
741        * {
742        *   public:
743        *     naRef myMethod(const nasal::CallContext& ctx);
744        * }
745        *
746        * Ghost<MyClassPtr>::init("Test")
747        *   .method("myMethod", &MyClass::myMethod);
748        * @endcode
749        */
750       Ghost& method(const std::string& name, const method_t& func)
751       {
752         _members[name].func = new MethodHolder(func);
753         return *this;
754       }
755
756       /**
757        * Register anything that accepts an object instance and a
758        * nasal::CallContext whith automatic conversion of the return type to
759        * Nasal.
760        *
761        * @code{cpp}
762        * class MyClass;
763        * void doIt(const MyClass& c, const nasal::CallContext& ctx);
764        *
765        * Ghost<MyClassPtr>::init("Test")
766        *   .method("doIt", &doIt);
767        * @endcode
768        */
769       template<class Ret>
770       Ghost& method
771       (
772         const std::string& name,
773         const boost::function<Ret (raw_type&, const CallContext&)>& func
774       )
775       {
776         return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
777       }
778
779       // Build dependency for CMake, gcc, etc.
780 #define SG_DONT_DO_ANYTHING
781 # include <simgear/nasal/cppbind/detail/functor_templates.hxx>
782 #undef SG_DONT_DO_ANYTHING
783
784 #define BOOST_PP_ITERATION_LIMITS (0, 9)
785 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
786 #include BOOST_PP_ITERATE()
787
788       /**
789        * Create a shared pointer on the heap to handle the reference counting
790        * for the passed shared pointer while it is used in Nasal space.
791        */
792       template<class RefType>
793       static
794       typename boost::enable_if_c<
795            boost::is_same<RefType, strong_ref>::value
796         || boost::is_same<RefType, weak_ref>::value,
797         naRef
798       >::type
799       makeGhost(naContext c, RefType const& ref_ptr)
800       {
801         strong_ref ref(ref_ptr);
802         raw_type* ptr = get_pointer(ref_ptr);
803         if( !ptr )
804           return naNil();
805
806         // We are wrapping shared pointers to already existing objects which
807         // will then be hold be a new shared pointer. We therefore have to
808         // check for the dynamic type of the object as it might differ from
809         // the passed static type.
810         naGhostType* ghost_type =
811           getTypeFor<Ghost>(ptr, shared_ptr_traits<RefType>::is_strong::value);
812
813         if( !ghost_type )
814           return naNil();
815
816         return naNewGhost2(c, ghost_type, new RefType(ref_ptr));
817       }
818
819       /**
820        * Convert Nasal object to C++ object. To get a valid object the passed
821        * Nasal objects has to be derived class of the target class (Either
822        * derived in C++ or in Nasal using a 'parents' vector)
823        */
824       template<class RefType>
825       static
826       typename boost::enable_if_c<
827            boost::is_same<RefType, strong_ref>::value
828         || boost::is_same<RefType, weak_ref>::value,
829         RefType
830       >::type
831       fromNasal(naContext c, naRef me)
832       {
833         bool is_weak = false;
834
835         // Check if it's a ghost and if it can be converted
836         if( isBaseOf(naGhost_type(me), is_weak) )
837         {
838           void* ghost = naGhost_ptr(me);
839           return is_weak ? getPtr<RefType, true>(ghost)
840                          : getPtr<RefType, false>(ghost);
841         }
842
843         // Now if it is derived from a ghost (hash with ghost in parent vector)
844         else if( naIsHash(me) )
845         {
846           naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
847           if( !naIsVector(na_parents) )
848             return RefType();
849
850           typedef std::vector<naRef> naRefs;
851           naRefs parents = from_nasal<naRefs>(c, na_parents);
852           for( naRefs::const_iterator parent = parents.begin();
853                                       parent != parents.end();
854                                     ++parent )
855           {
856             RefType ptr = fromNasal<RefType>(c, *parent);
857             if( get_pointer(ptr) )
858               return ptr;
859           }
860         }
861
862         return RefType();
863       }
864
865       static bool isBaseOf(naRef obj)
866       {
867         bool is_weak;
868         return isBaseOf(naGhost_type(obj), is_weak);
869       }
870
871     private:
872
873       template<class>
874       friend class Ghost;
875
876       static naGhostType _ghost_type_strong, //!< Stored as shared pointer
877                          _ghost_type_weak;   //!< Stored as weak shared pointer
878
879       typedef naGhostType* (*type_checker_t)(const raw_type*, bool);
880       typedef std::vector<type_checker_t> DerivedList;
881       DerivedList _derived_types;
882
883       static bool isBaseOf(naGhostType* ghost_type, bool& is_weak)
884       {
885         if( !ghost_type || !getSingletonPtr() )
886           return false;
887
888         return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type, is_weak);
889       }
890
891       static bool isBaseOf(naRef obj, bool& is_weak)
892       {
893         return isBaseOf(naGhost_type(obj), is_weak);
894       }
895
896       template<class RefPtr, bool is_weak>
897       static
898       typename boost::enable_if_c<
899         !is_weak,
900         RefPtr
901       >::type
902       getPtr(void* ptr)
903       {
904         if( ptr )
905           return RefPtr(*static_cast<strong_ref*>(ptr));
906         else
907           return RefPtr();
908       }
909
910       template<class RefPtr, bool is_weak>
911       static
912       typename boost::enable_if_c<
913         is_weak && supports_weak_ref<T>::value,
914         RefPtr
915       >::type
916       getPtr(void* ptr)
917       {
918         if( ptr )
919           return RefPtr(*static_cast<weak_ref*>(ptr));
920         else
921           return RefPtr();
922       }
923
924       template<class RefPtr, bool is_weak>
925       static
926       typename boost::enable_if_c<
927         is_weak && !supports_weak_ref<T>::value,
928         RefPtr
929       >::type
930       getPtr(void* ptr)
931       {
932         return RefPtr();
933       }
934
935       void addDerived( const internal::GhostMetadata* derived_meta,
936                        type_checker_t derived_type_checker )
937       {
938         GhostMetadata::addDerived(derived_meta);
939         _derived_types.push_back(derived_type_checker);
940       }
941
942       template<class BaseGhost>
943       static
944       typename boost::enable_if
945         < boost::is_polymorphic<typename BaseGhost::raw_type>,
946           naGhostType*
947         >::type
948       getTypeFor(const typename BaseGhost::raw_type* base, bool strong)
949       {
950         // Check first if passed pointer can by converted to instance of class
951         // this ghost wraps.
952         if(   !boost::is_same
953                  < typename BaseGhost::raw_type,
954                    typename Ghost::raw_type
955                  >::value
956             && dynamic_cast<const typename Ghost::raw_type*>(base) != base )
957           return 0;
958
959         if( !getSingletonPtr() )
960         {
961           SG_LOG
962           (
963             SG_NASAL,
964             SG_INFO,
965             "Ghost::getTypeFor: can not get type for unregistered ghost"
966           );
967           return 0;
968         }
969
970         // Now check if we can further downcast to one of our derived classes.
971         for( typename DerivedList::reverse_iterator
972                derived = getSingletonPtr()->_derived_types.rbegin();
973                derived != getSingletonPtr()->_derived_types.rend();
974              ++derived )
975         {
976           naGhostType* ghost_type =
977             (*derived)(
978               static_cast<const typename Ghost::raw_type*>(base),
979               strong
980             );
981
982           if( ghost_type )
983             return ghost_type;
984         }
985
986         // If base is not an instance of any derived class, this class has to
987         // be the dynamic type.
988         return strong
989              ? &_ghost_type_strong
990              : &_ghost_type_weak;
991       }
992
993       template<class BaseGhost>
994       static
995       typename boost::disable_if
996         < boost::is_polymorphic<typename BaseGhost::raw_type>,
997           naGhostType*
998         >::type
999       getTypeFor(const typename BaseGhost::raw_type* base, bool strong)
1000       {
1001         // For non polymorphic classes there is no possibility to get the actual
1002         // dynamic type, therefore we can only use its static type.
1003         return strong
1004              ? &BaseGhost::_ghost_type_strong
1005              : &BaseGhost::_ghost_type_weak;
1006       }
1007
1008       static Ghost* getSingletonPtr()
1009       {
1010         return getSingletonHolder().get();
1011       }
1012
1013       static raw_type& requireObject(naContext c, naRef me)
1014       {
1015         raw_type* obj = get_pointer( fromNasal<strong_ref>(c, me) );
1016
1017         if( !obj )
1018         {
1019           naGhostType* ghost_type = naGhost_type(me);
1020           naRuntimeError
1021           (
1022             c,
1023             "method called on object of wrong type: is '%s' expected '%s'",
1024             naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
1025             _ghost_type_strong.name
1026           );
1027         }
1028
1029         return *obj;
1030       }
1031
1032       template<class Ret>
1033       getter_t to_getter(Ret (raw_type::*getter)() const)
1034       {
1035         typedef typename boost::call_traits<Ret>::param_type param_type;
1036         naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
1037
1038         // Getter signature: naRef(raw_type&, naContext)
1039         return boost::bind
1040         (
1041           to_nasal_,
1042           _2,
1043           boost::bind(getter, _1)
1044         );
1045       }
1046
1047       template<class Param>
1048       setter_t to_setter(void (raw_type::*setter)(Param))
1049       {
1050         // Setter signature: void(raw_type&, naContext, naRef)
1051         return boost::bind
1052         (
1053           setter,
1054           _1,
1055           boost::bind(from_nasal_ptr<Param>::get(), _2, _3)
1056         );
1057       }
1058
1059       /**
1060        * Invoke a method which writes the converted parameter to a reference
1061        */
1062       template<class Param>
1063       static
1064       bool convert_param_invoker
1065       (
1066         const boost::function<bool ( raw_type&,
1067                                      const std::string&,
1068                                      Param& )>& func,
1069         raw_type& obj,
1070         naContext c,
1071         const std::string& key,
1072         naRef& out
1073       )
1074       {
1075         Param p;
1076         if( !func(obj, key, p) )
1077           return false;
1078
1079         out = to_nasal(c, p);
1080         return true;
1081       };
1082
1083       /**
1084        * Invoke a method which returns a value and convert it to Nasal.
1085        */
1086       template<class Ret>
1087       static
1088       typename boost::disable_if<boost::is_void<Ret>, naRef>::type
1089       method_invoker
1090       (
1091         const boost::function<Ret (raw_type&, const CallContext&)>& func,
1092         raw_type& obj,
1093         const CallContext& ctx
1094       )
1095       {
1096         return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
1097       };
1098
1099       /**
1100        * Invoke a method which returns void and "convert" it to nil.
1101        */
1102       template<class Ret>
1103       static
1104       typename boost::enable_if<boost::is_void<Ret>, naRef>::type
1105       method_invoker
1106       (
1107         const boost::function<Ret (raw_type&, const CallContext&)>& func,
1108         raw_type& obj,
1109         const CallContext& ctx
1110       )
1111       {
1112         func(obj, ctx);
1113         return naNil();
1114       };
1115
1116       /**
1117        * Extract argument by index from nasal::CallContext and convert to given
1118        * type.
1119        */
1120       template<class Arg>
1121       static
1122       typename boost::disable_if<
1123         internal::reduced_is_same<Arg, CallContext>,
1124         typename from_nasal_ptr<Arg>::return_type
1125       >::type
1126       arg_from_nasal(const CallContext& ctx, size_t index)
1127       {
1128         return ctx.requireArg<Arg>(index);
1129       };
1130
1131       /**
1132        * Specialization to pass through nasal::CallContext.
1133        */
1134       template<class Arg>
1135       static
1136       typename boost::enable_if<
1137         internal::reduced_is_same<Arg, CallContext>,
1138         typename from_nasal_ptr<Arg>::return_type
1139       >::type
1140       arg_from_nasal(const CallContext& ctx, size_t)
1141       {
1142         // Either const CallContext& or CallContext, non-const reference
1143         // does not make sense.
1144         BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
1145         return ctx;
1146       };
1147
1148       typedef std::auto_ptr<Ghost> GhostPtr;
1149       MemberMap         _members;
1150       fallback_getter_t _fallback_getter;
1151       fallback_setter_t _fallback_setter;
1152
1153       explicit Ghost(const std::string& name):
1154         GhostMetadata( name,
1155                        &_ghost_type_strong,
1156                        supports_weak_ref<T>::value ? &_ghost_type_weak : NULL )
1157       {
1158         _ghost_type_strong.destroy = &destroy<strong_ref>;
1159         _ghost_type_strong.name = _name_strong.c_str();
1160         _ghost_type_strong.get_member = &getMember<false>;
1161         _ghost_type_strong.set_member = &setMember<false>;
1162
1163         _ghost_type_weak.destroy = &destroy<weak_ref>;
1164         _ghost_type_weak.name = _name_weak.c_str();
1165
1166         bool can_weak = supports_weak_ref<T>::value;
1167         _ghost_type_weak.get_member = can_weak ? &getMember<true> : 0;
1168         _ghost_type_weak.set_member = can_weak ? &setMember<true> : 0;
1169       }
1170
1171       static GhostPtr& getSingletonHolder()
1172       {
1173         static GhostPtr instance;
1174         return instance;
1175       }
1176
1177       template<class Type>
1178       static void destroy(void *ptr)
1179       {
1180         delete static_cast<Type*>(ptr);
1181       }
1182
1183       /**
1184        * Callback for retrieving a ghost member.
1185        */
1186       static const char* getMember( naContext c,
1187                                     raw_type& obj,
1188                                     naRef key,
1189                                     naRef* out )
1190       {
1191         const std::string key_str = nasal::from_nasal<std::string>(c, key);
1192         // TODO merge instance parents with static class parents
1193 //        if( key_str == "parents" )
1194 //        {
1195 //          if( getSingletonPtr()->_parents.empty() )
1196 //            return 0;
1197 //
1198 //          *out = getSingletonPtr()->getParents(c);
1199 //          return "";
1200 //        }
1201
1202         typename MemberMap::iterator member =
1203           getSingletonPtr()->_members.find(key_str);
1204
1205         if( member == getSingletonPtr()->_members.end() )
1206         {
1207           fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
1208           if(    !fallback_get
1209               || !fallback_get(obj, c, key_str, *out) )
1210             return 0;
1211         }
1212         else if( member->second.func )
1213           *out = member->second.func->get_naRef(c);
1214         else if( !member->second.getter.empty() )
1215           *out = member->second.getter(obj, c);
1216         else
1217           return "Read-protected member";
1218
1219         return "";
1220       }
1221
1222       template<bool is_weak>
1223       static const char* getMember( naContext c,
1224                                     void* ghost,
1225                                     naRef key,
1226                                     naRef* out )
1227       {
1228         strong_ref const& ptr = getPtr<strong_ref, is_weak>(ghost);
1229         return getMember(c, *get_pointer(ptr), key, out);
1230       }
1231
1232       /**
1233        * Callback for writing to a ghost member.
1234        */
1235       static void setMember( naContext c,
1236                              raw_type& obj,
1237                              naRef field,
1238                              naRef val )
1239       {
1240         const std::string key = nasal::from_nasal<std::string>(c, field);
1241         const MemberMap& members = getSingletonPtr()->_members;
1242
1243         typename MemberMap::const_iterator member = members.find(key);
1244         if( member == members.end() )
1245         {
1246           fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
1247           if( !fallback_set )
1248             naRuntimeError(c, "ghost: No such member: %s", key.c_str());
1249           else if( !fallback_set(obj, c, key, val) )
1250             naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
1251         }
1252         else if( member->second.setter.empty() )
1253           naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
1254         else if( member->second.func )
1255           naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
1256         else
1257           member->second.setter(obj, c, val);
1258       }
1259
1260       template<bool is_weak>
1261       static void setMember( naContext c,
1262                              void* ghost,
1263                              naRef field,
1264                              naRef val )
1265       {
1266         strong_ref const& ptr = getPtr<strong_ref, is_weak>(ghost);
1267         return setMember(c, *get_pointer(ptr), field, val);
1268       }
1269   };
1270
1271   template<class T>
1272   naGhostType Ghost<T>::_ghost_type_strong;
1273   template<class T>
1274   naGhostType Ghost<T>::_ghost_type_weak;
1275
1276 } // namespace nasal
1277
1278 // Needs to be outside any namespace to make ADL work
1279 /**
1280  * Convert every shared pointer to a ghost.
1281  */
1282 template<class T>
1283 typename boost::enable_if<
1284   nasal::internal::has_element_type<
1285     typename nasal::internal::reduced_type<T>::type
1286   >,
1287   naRef
1288 >::type
1289 to_nasal_helper(naContext c, T ptr)
1290 {
1291   typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
1292   return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
1293 }
1294
1295 /**
1296  * Convert nasal ghosts/hashes to shared pointer (of a ghost).
1297  */
1298 template<class T>
1299 typename boost::enable_if<
1300   nasal::internal::has_element_type<
1301     typename nasal::internal::reduced_type<T>::type
1302   >,
1303   T
1304 >::type
1305 from_nasal_helper(naContext c, naRef ref, const T*)
1306 {
1307   typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
1308   return nasal::Ghost<strong_ref>::template fromNasal<T>(c, ref);
1309 }
1310
1311 /**
1312  * Convert any pointer to a SGReference based object to a ghost.
1313  */
1314 template<class T>
1315 typename boost::enable_if_c<
1316      boost::is_base_of<SGReferenced, T>::value
1317   || boost::is_base_of<SGWeakReferenced, T>::value,
1318   naRef
1319 >::type
1320 to_nasal_helper(naContext c, T* ptr)
1321 {
1322   return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
1323 }
1324
1325 /**
1326  * Convert nasal ghosts/hashes to pointer (of a SGReference based ghost).
1327  */
1328 template<class T>
1329 typename boost::enable_if_c<
1330      boost::is_base_of<
1331        SGReferenced,
1332        typename boost::remove_pointer<T>::type
1333      >::value
1334   || boost::is_base_of<
1335        SGWeakReferenced,
1336        typename boost::remove_pointer<T>::type
1337      >::value,
1338   T
1339 >::type
1340 from_nasal_helper(naContext c, naRef ref, const T*)
1341 {
1342   typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
1343   return nasal::Ghost<TypeRef>::template fromNasal<TypeRef>(c, ref).release();
1344 }
1345
1346 #endif /* SG_NASAL_GHOST_HXX_ */