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