]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/cppbind/Ghost.hxx
SGSharedPtr/SGWeakPtr: add some methods/operators
[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(naContext, raw_type&)>          getter_t;
221       typedef boost::function<void(naContext, raw_type&, naRef)>    setter_t;
222       typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
223       typedef boost::function<bool( naContext,
224                                     raw_type&,
225                                     const std::string&,
226                                     naRef )>               fallback_setter_t;
227
228       class MethodHolder:
229         public internal::MethodHolder
230       {
231         public:
232           explicit MethodHolder(const method_t& method):
233             _method(method)
234           {}
235
236         protected:
237
238           typedef SGSharedPtr<MethodHolder> SharedPtr;
239           typedef SGWeakPtr<MethodHolder> WeakPtr;
240
241           method_t  _method;
242
243           virtual naRef createNasalObject(naContext c)
244           {
245             return naNewFunc
246             (
247               c,
248               naNewCCodeUD( c,
249                             &MethodHolder::call,
250                             new WeakPtr(this),
251                             &destroyHolder )
252             );
253           }
254
255           static void destroyHolder(void* user_data)
256           {
257             delete static_cast<WeakPtr*>(user_data);
258           }
259
260           static naRef call( naContext c,
261                              naRef me,
262                              int argc,
263                              naRef* args,
264                              void* user_data )
265           {
266             WeakPtr* holder_weak = static_cast<WeakPtr*>(user_data);
267             if( !holder_weak )
268               naRuntimeError(c, "invalid method holder!");
269
270             try
271             {
272               SharedPtr holder = holder_weak->lock();
273               if( !holder )
274                 throw std::runtime_error("holder has expired");
275
276               return holder->_method
277               (
278                 requireObject(c, me),
279                 CallContext(c, argc, args)
280               );
281             }
282             catch(const std::exception& ex)
283             {
284               naRuntimeError(c, "Fatal error in method call: %s", ex.what());
285             }
286             catch(...)
287             {
288               naRuntimeError(c, "Unknown exception in method call.");
289             }
290
291             return naNil();
292           }
293       };
294
295       /**
296        * A ghost member. Can consist either of getter and/or setter functions
297        * for exposing a data variable or a single callable function.
298        */
299       struct member_t
300       {
301         member_t()
302         {}
303
304         member_t( const getter_t& getter,
305                   const setter_t& setter,
306                   const MethodHolderPtr& func = MethodHolderPtr() ):
307           getter( getter ),
308           setter( setter ),
309           func( func )
310         {}
311
312         explicit member_t(const MethodHolderPtr& func):
313           func( func )
314         {}
315
316         getter_t        getter;
317         setter_t        setter;
318         MethodHolderPtr func;
319       };
320
321       typedef std::map<std::string, member_t> MemberMap;
322
323       /**
324        * Register a new ghost type.
325        *
326        * @note Only intialize each ghost type once!
327        *
328        * @param name    Descriptive name of the ghost type.
329        */
330       static Ghost& init(const std::string& name)
331       {
332         getSingletonHolder().reset( new Ghost(name) );
333         return *getSingletonPtr();
334       }
335
336       /**
337        * Check whether ghost type has already been initialized.
338        */
339       static bool isInit()
340       {
341         return getSingletonPtr();
342       }
343
344       /**
345        * Register a base class for this ghost. The base class needs to be
346        * registers on its own before it can be used as base class.
347        *
348        * @tparam BaseGhost  Type of base class already wrapped into Ghost class
349        *                    (Ghost<BasePtr>)
350        *
351        * @code{cpp}
352        * Ghost<MyBasePtr>::init("MyBase");
353        * Ghost<MyClassPtr>::init("MyClass")
354        *   .bases<Ghost<MyBasePtr> >();
355        * @endcode
356        */
357       template<class BaseGhost>
358       typename boost::enable_if
359         <
360           boost::is_base_of<GhostMetadata, BaseGhost>,
361           Ghost
362         >::type&
363       bases()
364       {
365         BOOST_STATIC_ASSERT
366         ((
367           boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
368         ));
369
370         BaseGhost* base = BaseGhost::getSingletonPtr();
371         base->addDerived
372         (
373           this,
374           // Both ways of retrieving the address of a static member function
375           // should be legal but not all compilers know this.
376           // g++-4.4.7+ has been tested to work with both versions
377 #if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407
378           // The old version of g++ used on Jenkins (16.11.2012) only compiles
379           // this version.
380           &getTypeFor<BaseGhost>
381 #else
382           // VS (2008, 2010, ... ?) only allow this version.
383           &Ghost::getTypeFor<BaseGhost>
384 #endif
385         );
386
387         // Replace any getter that is not available in the current class.
388         // TODO check if this is the correct behavior of function overriding
389         for( typename BaseGhost::MemberMap::const_iterator member =
390                base->_members.begin();
391                member != base->_members.end();
392              ++member )
393         {
394           if( _members.find(member->first) == _members.end() )
395             _members[member->first] = member_t
396             (
397               member->second.getter,
398               member->second.setter,
399               member->second.func
400             );
401         }
402
403         if( !_fallback_setter )
404           _fallback_setter = base->_fallback_setter;
405
406         return *this;
407       }
408
409       /**
410        * Register a base class for this ghost. The base class needs to be
411        * registers on its own before it can be used as base class.
412        *
413        * @tparam Base   Type of base class (Base as used in Ghost<BasePtr>)
414        *
415        * @code{cpp}
416        * Ghost<MyBasePtr>::init("MyBase");
417        * Ghost<MyClassPtr>::init("MyClass")
418        *   .bases<MyBasePtr>();
419        * @endcode
420        */
421       template<class Base>
422       typename boost::disable_if
423         <
424           boost::is_base_of<GhostMetadata, Base>,
425           Ghost
426         >::type&
427       bases()
428       {
429         BOOST_STATIC_ASSERT
430         ((
431           boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
432         ));
433
434         return bases< Ghost<Base> >();
435       }
436
437       /**
438        * Register an existing Nasal class/hash as base class for this ghost.
439        *
440        * @param parent  Nasal hash/class
441        */
442       Ghost& bases(const naRef& parent)
443       {
444         addNasalBase(parent);
445         return *this;
446       }
447
448       /**
449        * Register a member variable by passing a getter and/or setter method.
450        *
451        * @param field   Name of member
452        * @param getter  Getter for variable
453        * @param setter  Setter for variable (Pass 0 to prevent write access)
454        *
455        */
456       template<class Ret, class Param>
457       Ghost& member( const std::string& field,
458                      Ret (raw_type::*getter)() const,
459                      void (raw_type::*setter)(Param) )
460       {
461         return member(field, to_getter(getter), to_setter(setter));
462       }
463
464       /**
465        * Register a read only member variable.
466        *
467        * @param field   Name of member
468        * @param getter  Getter for variable
469        */
470       template<class Ret>
471       Ghost& member( const std::string& field,
472                      Ret (raw_type::*getter)() const )
473       {
474         return member(field, to_getter(getter), setter_t());
475       }
476
477       /**
478        * Register a write only member variable.
479        *
480        * @param field   Name of member
481        * @param setter  Setter for variable
482        */
483       template<class Var>
484       Ghost& member( const std::string& field,
485                      void (raw_type::*setter)(Var) )
486       {
487         return member(field, getter_t(), to_setter(setter));
488       }
489
490       /**
491        * Register a member variable by passing a getter and/or setter method.
492        *
493        * @param field   Name of member
494        * @param getter  Getter for variable
495        * @param setter  Setter for variable (Pass empty to prevent write access)
496        *
497        */
498       Ghost& member( const std::string& field,
499                      const getter_t& getter,
500                      const setter_t& setter = setter_t() )
501       {
502         if( !getter.empty() || !setter.empty() )
503           _members[field] = member_t(getter, setter);
504         else
505           SG_LOG
506           (
507             SG_NASAL,
508             SG_WARN,
509             "Member '" << field << "' requires a getter or setter"
510           );
511         return *this;
512       }
513
514       /**
515        * Register a function which is called upon setting an unknown member of
516        * this ghost.
517        */
518       Ghost& _set(const fallback_setter_t& setter)
519       {
520         _fallback_setter = setter;
521         return *this;
522       }
523
524       /**
525        * Register a method which is called upon setting an unknown member of
526        * this ghost.
527        *
528        * @code{cpp}
529        * class MyClass
530        * {
531        *   public:
532        *     bool setMember( const std::string& key,
533        *                     const std::string& value );
534        * }
535        *
536        * Ghost<MyClassPtr>::init("Test")
537        *   ._set(&MyClass::setMember);
538        * @endcode
539        */
540       template<class Param>
541       Ghost _set(bool (raw_type::*setter)(const std::string&, Param))
542       {
543         // Setter signature: bool( naContext,
544         //                         raw_type&,
545         //                         const std::string&,
546         //                         naRef )
547         return _set(boost::bind(
548           setter,
549           _2,
550           _3,
551           boost::bind(from_nasal_ptr<Param>::get(), _1, _4)
552         ));
553       }
554
555       /**
556        * Register anything that accepts an object instance and a
557        * nasal::CallContext and returns naRef as method.
558        *
559        * @code{cpp}
560        * class MyClass
561        * {
562        *   public:
563        *     naRef myMethod(const nasal::CallContext& ctx);
564        * }
565        *
566        * Ghost<MyClassPtr>::init("Test")
567        *   .method("myMethod", &MyClass::myMethod);
568        * @endcode
569        */
570       Ghost& method(const std::string& name, const method_t& func)
571       {
572         _members[name].func = new MethodHolder(func);
573         return *this;
574       }
575
576       /**
577        * Register anything that accepts an object instance and a
578        * nasal::CallContext whith automatic conversion of the return type to
579        * Nasal.
580        *
581        * @code{cpp}
582        * class MyClass;
583        * void doIt(const MyClass& c, const nasal::CallContext& ctx);
584        *
585        * Ghost<MyClassPtr>::init("Test")
586        *   .method("doIt", &doIt);
587        * @endcode
588        */
589       template<class Ret>
590       Ghost& method
591       (
592         const std::string& name,
593         const boost::function<Ret (raw_type&, const CallContext&)>& func
594       )
595       {
596         return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
597       }
598
599       // Build dependency for CMake, gcc, etc.
600 #define SG_DONT_DO_ANYTHING
601 # include <simgear/nasal/cppbind/detail/functor_templates.hxx>
602 #undef SG_DONT_DO_ANYTHING
603
604 #define BOOST_PP_ITERATION_LIMITS (0, 9)
605 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
606 #include BOOST_PP_ITERATE()
607
608       // TODO use variadic template when supporting C++11
609       // TODO check if default constructor exists
610 //      static naRef create( naContext c )
611 //      {
612 //        return makeGhost(c, createInstance());
613 //      }
614
615       /**
616        * Create a Nasal instance of this ghost.
617        *
618        * @param c   Active Nasal context
619        * @param a1  Parameter used for creating new instance
620        */
621       template<class A1>
622       static naRef create( naContext c, const A1& a1 )
623       {
624         return makeGhost(c, createInstance(a1));
625       }
626
627       /**
628        * Nasal callback for creating a new instance of this ghost.
629        */
630       static naRef f_create(naContext c, naRef me, int argc, naRef* args)
631       {
632         return create(c);
633       }
634
635       static bool isBaseOf(naGhostType* ghost_type)
636       {
637         if( !ghost_type )
638           return false;
639
640         return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type);
641       }
642
643       static bool isBaseOf(naRef obj)
644       {
645         return isBaseOf( naGhost_type(obj) );
646       }
647
648       /**
649        * Convert Nasal object to C++ object. To get a valid object the passed
650        * Nasal objects has to be derived class of the target class (Either
651        * derived in C++ or in Nasal using a 'parents' vector)
652        */
653       static pointer fromNasal(naContext c, naRef me)
654       {
655         // Check if it's a ghost and if it can be converted
656         if( isBaseOf( naGhost_type(me) ) )
657           return getPtr( naGhost_ptr(me) );
658
659         // Now if it is derived from a ghost (hash with ghost in parent vector)
660         else if( naIsHash(me) )
661         {
662           naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
663           if( !naIsVector(na_parents) )
664             return pointer();
665
666           typedef std::vector<naRef> naRefs;
667           naRefs parents = from_nasal<naRefs>(c, na_parents);
668           for( naRefs::const_iterator parent = parents.begin();
669                                       parent != parents.end();
670                                     ++parent )
671           {
672             pointer ptr = fromNasal(c, *parent);
673             if( get_pointer(ptr) )
674               return ptr;
675           }
676         }
677
678         return pointer();
679       }
680
681     private:
682
683       template<class>
684       friend class Ghost;
685
686       static naGhostType _ghost_type;
687
688       typedef naGhostType* (*type_checker_t)(const raw_type*);
689       typedef std::vector<type_checker_t> DerivedList;
690       DerivedList _derived_types;
691
692       /**
693        * Create a shared pointer on the heap to handle the reference counting
694        * for the passed shared pointer while it is used in Nasal space.
695        */
696       static pointer* createInstance(const pointer& ptr)
697       {
698         return get_pointer(ptr) ? new pointer(ptr) : 0;
699       }
700
701       static pointer getPtr(void* ptr)
702       {
703         if( ptr )
704           return *static_cast<pointer*>(ptr);
705         else
706           return pointer();
707       }
708
709       static raw_type* getRawPtr(void* ptr)
710       {
711         if( ptr )
712           return get_pointer(*static_cast<pointer*>(ptr));
713         else
714           return 0;
715       }
716
717       static raw_type* getRawPtr(const pointer& ptr)
718       {
719         return get_pointer(ptr);
720       }
721
722       void addDerived( const internal::GhostMetadata* derived_meta,
723                        const type_checker_t& derived_info )
724       {
725         GhostMetadata::addDerived(derived_meta);
726         _derived_types.push_back(derived_info);
727       }
728
729       template<class BaseGhost>
730       static
731       typename boost::enable_if
732         < boost::is_polymorphic<typename BaseGhost::raw_type>,
733           naGhostType*
734         >::type
735       getTypeFor(const typename BaseGhost::raw_type* base)
736       {
737         // Check first if passed pointer can by converted to instance of class
738         // this ghost wraps.
739         if(   !boost::is_same
740                  < typename BaseGhost::raw_type,
741                    typename Ghost::raw_type
742                  >::value
743             && dynamic_cast<const typename Ghost::raw_type*>(base) != base )
744           return 0;
745
746         if( !getSingletonPtr() )
747         {
748           SG_LOG
749           (
750             SG_NASAL,
751             SG_INFO,
752             "Ghost::getTypeFor: can not get type for unregistered ghost"
753           );
754           return 0;
755         }
756
757         // Now check if we can further downcast to one of our derived classes.
758         for( typename DerivedList::reverse_iterator
759                derived = getSingletonPtr()->_derived_types.rbegin();
760                derived != getSingletonPtr()->_derived_types.rend();
761              ++derived )
762         {
763           naGhostType* ghost_type =
764             (*derived)( static_cast<const typename Ghost::raw_type*>(base) );
765           if( ghost_type )
766             return ghost_type;
767         }
768
769         // If base is not an instance of any derived class, this class has to
770         // be the dynamic type.
771         return &_ghost_type;
772       }
773
774       template<class BaseGhost>
775       static
776       typename boost::disable_if
777         < boost::is_polymorphic<typename BaseGhost::raw_type>,
778           naGhostType*
779         >::type
780       getTypeFor(const typename BaseGhost::raw_type* base)
781       {
782         // For non polymorphic classes there is no possibility to get the actual
783         // dynamic type, therefore we can only use its static type.
784         return &BaseGhost::_ghost_type;
785       }
786
787       static Ghost* getSingletonPtr()
788       {
789         return getSingletonHolder().get();
790       }
791
792       static raw_type& requireObject(naContext c, naRef me)
793       {
794         raw_type* obj = getRawPtr( fromNasal(c, me) );
795         naGhostType* ghost_type = naGhost_type(me);
796
797         if( !obj )
798           naRuntimeError
799           (
800             c,
801             "method called on object of wrong type: is '%s' expected '%s'",
802             naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
803             _ghost_type.name
804           );
805
806         return *obj;
807       }
808
809       template<class Ret>
810       getter_t to_getter(Ret (raw_type::*getter)() const)
811       {
812         typedef typename boost::call_traits<Ret>::param_type param_type;
813         naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
814
815         // Getter signature: naRef(naContext, raw_type&)
816         return boost::bind
817         (
818           to_nasal_,
819           _1,
820           boost::bind(getter, _2)
821         );
822       }
823
824       template<class Param>
825       setter_t to_setter(void (raw_type::*setter)(Param))
826       {
827         // Setter signature: void(naContext, raw_type&, naRef)
828         return boost::bind
829         (
830           setter,
831           _2,
832           boost::bind(from_nasal_ptr<Param>::get(), _1, _3)
833         );
834       }
835
836
837       /**
838        * Invoke a method which returns a value and convert it to Nasal.
839        */
840       template<class Ret>
841       static
842       typename boost::disable_if<boost::is_void<Ret>, naRef>::type
843       method_invoker
844       (
845         const boost::function<Ret (raw_type&, const CallContext&)>& func,
846         raw_type& obj,
847         const CallContext& ctx
848       )
849       {
850         return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
851       };
852
853       /**
854        * Invoke a method which returns void and "convert" it to nil.
855        */
856       template<class Ret>
857       static
858       typename boost::enable_if<boost::is_void<Ret>, naRef>::type
859       method_invoker
860       (
861         const boost::function<Ret (raw_type&, const CallContext&)>& func,
862         raw_type& obj,
863         const CallContext& ctx
864       )
865       {
866         func(obj, ctx);
867         return naNil();
868       };
869
870       /**
871        * Extract argument by index from nasal::CallContext and convert to given
872        * type.
873        */
874       template<class Arg>
875       static
876       typename boost::disable_if<
877         internal::reduced_is_same<Arg, CallContext>,
878         typename from_nasal_ptr<Arg>::return_type
879       >::type
880       arg_from_nasal(const CallContext& ctx, size_t index)
881       {
882         return ctx.requireArg<Arg>(index);
883       };
884
885       /**
886        * Specialization to pass through nasal::CallContext.
887        */
888       template<class Arg>
889       static
890       typename boost::enable_if<
891         internal::reduced_is_same<Arg, CallContext>,
892         typename from_nasal_ptr<Arg>::return_type
893       >::type
894       arg_from_nasal(const CallContext& ctx, size_t)
895       {
896         // Either const CallContext& or CallContext, non-const reference
897         // does not make sense.
898         BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
899         return ctx;
900       };
901
902       typedef std::auto_ptr<Ghost> GhostPtr;
903       MemberMap         _members;
904       fallback_setter_t _fallback_setter;
905
906       explicit Ghost(const std::string& name):
907         GhostMetadata(name, &_ghost_type)
908       {
909         _ghost_type.destroy = &destroyGhost;
910         _ghost_type.name = _name.c_str();
911         _ghost_type.get_member = &getMember;
912         _ghost_type.set_member = &setMember;
913       }
914
915       static GhostPtr& getSingletonHolder()
916       {
917         static GhostPtr instance;
918         return instance;
919       }
920
921       static naRef makeGhost(naContext c, void *ptr)
922       {
923         if( getRawPtr(ptr) )
924         {
925           // We are wrapping shared pointers to already existing objects which
926           // will then be hold be a new shared pointer. We therefore have to
927           // check for the dynamic type of the object as it might differ from
928           // the passed static type.
929           naGhostType* ghost_type = getTypeFor<Ghost>( getRawPtr(ptr) );
930
931           if( ghost_type )
932             return naNewGhost2(c, ghost_type, ptr);
933         }
934
935         destroyGhost(ptr);
936         return naNil();
937       }
938
939       static void destroyGhost(void *ptr)
940       {
941         delete static_cast<pointer*>(ptr);
942       }
943
944       /**
945        * Callback for retrieving a ghost member.
946        */
947       static const char* getMember(naContext c, void* g, naRef key, naRef* out)
948       {
949         const std::string key_str = nasal::from_nasal<std::string>(c, key);
950         // TODO merge instance parents with static class parents
951 //        if( key_str == "parents" )
952 //        {
953 //          if( getSingletonPtr()->_parents.empty() )
954 //            return 0;
955 //
956 //          *out = getSingletonPtr()->getParents(c);
957 //          return "";
958 //        }
959
960         typename MemberMap::iterator member =
961           getSingletonPtr()->_members.find(key_str);
962
963         if( member == getSingletonPtr()->_members.end() )
964           return 0;
965
966         if( member->second.func )
967           *out = member->second.func->get_naRef(c);
968         else if( !member->second.getter.empty() )
969           *out = member->second.getter(c, *getRawPtr(g));
970         else
971           return "Read-protected member";
972
973         return "";
974       }
975
976       /**
977        * Callback for writing to a ghost member.
978        */
979       static void setMember(naContext c, void* g, naRef field, naRef val)
980       {
981         const std::string key = nasal::from_nasal<std::string>(c, field);
982         const MemberMap& members = getSingletonPtr()->_members;
983
984         typename MemberMap::const_iterator member = members.find(key);
985         if( member == members.end() )
986         {
987           fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
988           if( !fallback_set )
989             naRuntimeError(c, "ghost: No such member: %s", key.c_str());
990           else if( !fallback_set(c, *getRawPtr(g), key, val) )
991             naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
992         }
993         else if( member->second.setter.empty() )
994           naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
995         else if( member->second.func )
996           naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
997         else
998           member->second.setter(c, *getRawPtr(g), val);
999       }
1000   };
1001
1002   template<class T>
1003   naGhostType Ghost<T>::_ghost_type;
1004
1005 } // namespace nasal
1006
1007 // Needs to be outside any namespace to make ADL work
1008 /**
1009  * Convert every shared pointer to a ghost.
1010  */
1011 template<class T>
1012 typename boost::enable_if<
1013   nasal::internal::has_element_type<
1014     typename nasal::internal::reduced_type<T>::type
1015   >,
1016   naRef
1017 >::type
1018 to_nasal_helper(naContext c, T ptr)
1019 {
1020   return nasal::Ghost<T>::create(c, ptr);
1021 }
1022
1023 /**
1024  * Convert nasal ghosts/hashes to shared pointer (of a ghost).
1025  */
1026 template<class T>
1027 typename boost::enable_if<
1028   nasal::internal::has_element_type<
1029     typename nasal::internal::reduced_type<T>::type
1030   >,
1031   T
1032 >::type
1033 from_nasal_helper(naContext c, naRef ref, const T*)
1034 {
1035   return nasal::Ghost<T>::fromNasal(c, ref);
1036 }
1037
1038 /**
1039  * Convert any pointer to a SGReference based object to a ghost.
1040  */
1041 template<class T>
1042 typename boost::enable_if<boost::is_base_of<SGReferenced, T>, naRef>::type
1043 to_nasal_helper(naContext c, T* ptr)
1044 {
1045   return nasal::Ghost<SGSharedPtr<T> >::create(c, SGSharedPtr<T>(ptr));
1046 }
1047
1048 /**
1049  * Convert nasal ghosts/hashes to pointer (of a SGReference based ghost).
1050  */
1051 template<class T>
1052 typename boost::enable_if<
1053   boost::is_base_of<SGReferenced, typename boost::remove_pointer<T>::type>,
1054   T
1055 >::type
1056 from_nasal_helper(naContext c, naRef ref, const T*)
1057 {
1058   typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
1059   return nasal::Ghost<TypeRef>::fromNasal(c, ref).release();
1060 }
1061
1062 #endif /* SG_NASAL_GHOST_HXX_ */