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