]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/cppbind/Ghost.hxx
346f6fbba66757011ed89b17588b2ed9c42284c0
[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 a method which is called upon setting an unknown member of
557        * this ghost.
558        *
559        * @code{cpp}
560        * class MyClass
561        * {
562        *   public:
563        *     bool setMember( naContext c,
564        *                     const std::string& key,
565        *                     naRef value );
566        * }
567        *
568        * Ghost<MyClassPtr>::init("Test")
569        *   ._set(&MyClass::setMember);
570        * @endcode
571        */
572       Ghost& _set(bool (raw_type::*setter)( naContext,
573                                             const std::string&,
574                                             naRef ))
575       {
576         // Setter signature: bool( naContext,
577         //                         raw_type&,
578         //                         const std::string&,
579         //                         naRef )
580         return _set( boost::bind(setter, _2, _1, _3, _4) );
581       }
582
583       /**
584        * Register anything that accepts an object instance and a
585        * nasal::CallContext and returns naRef as method.
586        *
587        * @code{cpp}
588        * class MyClass
589        * {
590        *   public:
591        *     naRef myMethod(const nasal::CallContext& ctx);
592        * }
593        *
594        * Ghost<MyClassPtr>::init("Test")
595        *   .method("myMethod", &MyClass::myMethod);
596        * @endcode
597        */
598       Ghost& method(const std::string& name, const method_t& func)
599       {
600         _members[name].func = new MethodHolder(func);
601         return *this;
602       }
603
604       /**
605        * Register anything that accepts an object instance and a
606        * nasal::CallContext whith automatic conversion of the return type to
607        * Nasal.
608        *
609        * @code{cpp}
610        * class MyClass;
611        * void doIt(const MyClass& c, const nasal::CallContext& ctx);
612        *
613        * Ghost<MyClassPtr>::init("Test")
614        *   .method("doIt", &doIt);
615        * @endcode
616        */
617       template<class Ret>
618       Ghost& method
619       (
620         const std::string& name,
621         const boost::function<Ret (raw_type&, const CallContext&)>& func
622       )
623       {
624         return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
625       }
626
627       // Build dependency for CMake, gcc, etc.
628 #define SG_DONT_DO_ANYTHING
629 # include <simgear/nasal/cppbind/detail/functor_templates.hxx>
630 #undef SG_DONT_DO_ANYTHING
631
632 #define BOOST_PP_ITERATION_LIMITS (0, 9)
633 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
634 #include BOOST_PP_ITERATE()
635
636       // TODO use variadic template when supporting C++11
637       // TODO check if default constructor exists
638 //      static naRef create( naContext c )
639 //      {
640 //        return makeGhost(c, createInstance());
641 //      }
642
643       /**
644        * Create a Nasal instance of this ghost.
645        *
646        * @param c   Active Nasal context
647        * @param a1  Parameter used for creating new instance
648        */
649       template<class A1>
650       static naRef create( naContext c, const A1& a1 )
651       {
652         return makeGhost(c, createInstance(a1));
653       }
654
655       /**
656        * Nasal callback for creating a new instance of this ghost.
657        */
658       static naRef f_create(naContext c, naRef me, int argc, naRef* args)
659       {
660         return create(c);
661       }
662
663       static bool isBaseOf(naGhostType* ghost_type)
664       {
665         if( !ghost_type )
666           return false;
667
668         return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type);
669       }
670
671       static bool isBaseOf(naRef obj)
672       {
673         return isBaseOf( naGhost_type(obj) );
674       }
675
676       /**
677        * Convert Nasal object to C++ object. To get a valid object the passed
678        * Nasal objects has to be derived class of the target class (Either
679        * derived in C++ or in Nasal using a 'parents' vector)
680        */
681       static pointer fromNasal(naContext c, naRef me)
682       {
683         // Check if it's a ghost and if it can be converted
684         if( isBaseOf( naGhost_type(me) ) )
685           return getPtr( naGhost_ptr(me) );
686
687         // Now if it is derived from a ghost (hash with ghost in parent vector)
688         else if( naIsHash(me) )
689         {
690           naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
691           if( !naIsVector(na_parents) )
692             return pointer();
693
694           typedef std::vector<naRef> naRefs;
695           naRefs parents = from_nasal<naRefs>(c, na_parents);
696           for( naRefs::const_iterator parent = parents.begin();
697                                       parent != parents.end();
698                                     ++parent )
699           {
700             pointer ptr = fromNasal(c, *parent);
701             if( get_pointer(ptr) )
702               return ptr;
703           }
704         }
705
706         return pointer();
707       }
708
709     private:
710
711       template<class>
712       friend class Ghost;
713
714       static naGhostType _ghost_type;
715
716       typedef naGhostType* (*type_checker_t)(const raw_type*);
717       typedef std::vector<type_checker_t> DerivedList;
718       DerivedList _derived_types;
719
720       /**
721        * Create a shared pointer on the heap to handle the reference counting
722        * for the passed shared pointer while it is used in Nasal space.
723        */
724       static pointer* createInstance(const pointer& ptr)
725       {
726         return get_pointer(ptr) ? new pointer(ptr) : 0;
727       }
728
729       static pointer getPtr(void* ptr)
730       {
731         if( ptr )
732           return *static_cast<pointer*>(ptr);
733         else
734           return pointer();
735       }
736
737       static raw_type* getRawPtr(void* ptr)
738       {
739         if( ptr )
740           return get_pointer(*static_cast<pointer*>(ptr));
741         else
742           return 0;
743       }
744
745       static raw_type* getRawPtr(const pointer& ptr)
746       {
747         return get_pointer(ptr);
748       }
749
750       void addDerived( const internal::GhostMetadata* derived_meta,
751                        const type_checker_t& derived_info )
752       {
753         GhostMetadata::addDerived(derived_meta);
754         _derived_types.push_back(derived_info);
755       }
756
757       template<class BaseGhost>
758       static
759       typename boost::enable_if
760         < boost::is_polymorphic<typename BaseGhost::raw_type>,
761           naGhostType*
762         >::type
763       getTypeFor(const typename BaseGhost::raw_type* base)
764       {
765         // Check first if passed pointer can by converted to instance of class
766         // this ghost wraps.
767         if(   !boost::is_same
768                  < typename BaseGhost::raw_type,
769                    typename Ghost::raw_type
770                  >::value
771             && dynamic_cast<const typename Ghost::raw_type*>(base) != base )
772           return 0;
773
774         if( !getSingletonPtr() )
775         {
776           SG_LOG
777           (
778             SG_NASAL,
779             SG_INFO,
780             "Ghost::getTypeFor: can not get type for unregistered ghost"
781           );
782           return 0;
783         }
784
785         // Now check if we can further downcast to one of our derived classes.
786         for( typename DerivedList::reverse_iterator
787                derived = getSingletonPtr()->_derived_types.rbegin();
788                derived != getSingletonPtr()->_derived_types.rend();
789              ++derived )
790         {
791           naGhostType* ghost_type =
792             (*derived)( static_cast<const typename Ghost::raw_type*>(base) );
793           if( ghost_type )
794             return ghost_type;
795         }
796
797         // If base is not an instance of any derived class, this class has to
798         // be the dynamic type.
799         return &_ghost_type;
800       }
801
802       template<class BaseGhost>
803       static
804       typename boost::disable_if
805         < boost::is_polymorphic<typename BaseGhost::raw_type>,
806           naGhostType*
807         >::type
808       getTypeFor(const typename BaseGhost::raw_type* base)
809       {
810         // For non polymorphic classes there is no possibility to get the actual
811         // dynamic type, therefore we can only use its static type.
812         return &BaseGhost::_ghost_type;
813       }
814
815       static Ghost* getSingletonPtr()
816       {
817         return getSingletonHolder().get();
818       }
819
820       static raw_type& requireObject(naContext c, naRef me)
821       {
822         raw_type* obj = getRawPtr( fromNasal(c, me) );
823         naGhostType* ghost_type = naGhost_type(me);
824
825         if( !obj )
826           naRuntimeError
827           (
828             c,
829             "method called on object of wrong type: is '%s' expected '%s'",
830             naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
831             _ghost_type.name
832           );
833
834         return *obj;
835       }
836
837       template<class Ret>
838       getter_t to_getter(Ret (raw_type::*getter)() const)
839       {
840         typedef typename boost::call_traits<Ret>::param_type param_type;
841         naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
842
843         // Getter signature: naRef(naContext, raw_type&)
844         return boost::bind
845         (
846           to_nasal_,
847           _1,
848           boost::bind(getter, _2)
849         );
850       }
851
852       template<class Param>
853       setter_t to_setter(void (raw_type::*setter)(Param))
854       {
855         // Setter signature: void(naContext, raw_type&, naRef)
856         return boost::bind
857         (
858           setter,
859           _2,
860           boost::bind(from_nasal_ptr<Param>::get(), _1, _3)
861         );
862       }
863
864
865       /**
866        * Invoke a method which returns a value and convert it to Nasal.
867        */
868       template<class Ret>
869       static
870       typename boost::disable_if<boost::is_void<Ret>, naRef>::type
871       method_invoker
872       (
873         const boost::function<Ret (raw_type&, const CallContext&)>& func,
874         raw_type& obj,
875         const CallContext& ctx
876       )
877       {
878         return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
879       };
880
881       /**
882        * Invoke a method which returns void and "convert" it to nil.
883        */
884       template<class Ret>
885       static
886       typename boost::enable_if<boost::is_void<Ret>, naRef>::type
887       method_invoker
888       (
889         const boost::function<Ret (raw_type&, const CallContext&)>& func,
890         raw_type& obj,
891         const CallContext& ctx
892       )
893       {
894         func(obj, ctx);
895         return naNil();
896       };
897
898       /**
899        * Extract argument by index from nasal::CallContext and convert to given
900        * type.
901        */
902       template<class Arg>
903       static
904       typename boost::disable_if<
905         internal::reduced_is_same<Arg, CallContext>,
906         typename from_nasal_ptr<Arg>::return_type
907       >::type
908       arg_from_nasal(const CallContext& ctx, size_t index)
909       {
910         return ctx.requireArg<Arg>(index);
911       };
912
913       /**
914        * Specialization to pass through nasal::CallContext.
915        */
916       template<class Arg>
917       static
918       typename boost::enable_if<
919         internal::reduced_is_same<Arg, CallContext>,
920         typename from_nasal_ptr<Arg>::return_type
921       >::type
922       arg_from_nasal(const CallContext& ctx, size_t)
923       {
924         // Either const CallContext& or CallContext, non-const reference
925         // does not make sense.
926         BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
927         return ctx;
928       };
929
930       typedef std::auto_ptr<Ghost> GhostPtr;
931       MemberMap         _members;
932       fallback_setter_t _fallback_setter;
933
934       explicit Ghost(const std::string& name):
935         GhostMetadata(name, &_ghost_type)
936       {
937         _ghost_type.destroy = &destroyGhost;
938         _ghost_type.name = _name.c_str();
939         _ghost_type.get_member = &getMember;
940         _ghost_type.set_member = &setMember;
941       }
942
943       static GhostPtr& getSingletonHolder()
944       {
945         static GhostPtr instance;
946         return instance;
947       }
948
949       static naRef makeGhost(naContext c, void *ptr)
950       {
951         if( getRawPtr(ptr) )
952         {
953           // We are wrapping shared pointers to already existing objects which
954           // will then be hold be a new shared pointer. We therefore have to
955           // check for the dynamic type of the object as it might differ from
956           // the passed static type.
957           naGhostType* ghost_type = getTypeFor<Ghost>( getRawPtr(ptr) );
958
959           if( ghost_type )
960             return naNewGhost2(c, ghost_type, ptr);
961         }
962
963         destroyGhost(ptr);
964         return naNil();
965       }
966
967       static void destroyGhost(void *ptr)
968       {
969         delete static_cast<pointer*>(ptr);
970       }
971
972       /**
973        * Callback for retrieving a ghost member.
974        */
975       static const char* getMember(naContext c, void* g, naRef key, naRef* out)
976       {
977         const std::string key_str = nasal::from_nasal<std::string>(c, key);
978         // TODO merge instance parents with static class parents
979 //        if( key_str == "parents" )
980 //        {
981 //          if( getSingletonPtr()->_parents.empty() )
982 //            return 0;
983 //
984 //          *out = getSingletonPtr()->getParents(c);
985 //          return "";
986 //        }
987
988         typename MemberMap::iterator member =
989           getSingletonPtr()->_members.find(key_str);
990
991         if( member == getSingletonPtr()->_members.end() )
992           return 0;
993
994         if( member->second.func )
995           *out = member->second.func->get_naRef(c);
996         else if( !member->second.getter.empty() )
997           *out = member->second.getter(c, *getRawPtr(g));
998         else
999           return "Read-protected member";
1000
1001         return "";
1002       }
1003
1004       /**
1005        * Callback for writing to a ghost member.
1006        */
1007       static void setMember(naContext c, void* g, naRef field, naRef val)
1008       {
1009         const std::string key = nasal::from_nasal<std::string>(c, field);
1010         const MemberMap& members = getSingletonPtr()->_members;
1011
1012         typename MemberMap::const_iterator member = members.find(key);
1013         if( member == members.end() )
1014         {
1015           fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
1016           if( !fallback_set )
1017             naRuntimeError(c, "ghost: No such member: %s", key.c_str());
1018           else if( !fallback_set(c, *getRawPtr(g), key, val) )
1019             naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
1020         }
1021         else if( member->second.setter.empty() )
1022           naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
1023         else if( member->second.func )
1024           naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
1025         else
1026           member->second.setter(c, *getRawPtr(g), val);
1027       }
1028   };
1029
1030   template<class T>
1031   naGhostType Ghost<T>::_ghost_type;
1032
1033 } // namespace nasal
1034
1035 // Needs to be outside any namespace to make ADL work
1036 /**
1037  * Convert every shared pointer to a ghost.
1038  */
1039 template<class T>
1040 typename boost::enable_if<
1041   nasal::internal::has_element_type<
1042     typename nasal::internal::reduced_type<T>::type
1043   >,
1044   naRef
1045 >::type
1046 to_nasal_helper(naContext c, T ptr)
1047 {
1048   return nasal::Ghost<T>::create(c, ptr);
1049 }
1050
1051 /**
1052  * Convert nasal ghosts/hashes to shared pointer (of a ghost).
1053  */
1054 template<class T>
1055 typename boost::enable_if<
1056   nasal::internal::has_element_type<
1057     typename nasal::internal::reduced_type<T>::type
1058   >,
1059   T
1060 >::type
1061 from_nasal_helper(naContext c, naRef ref, const T*)
1062 {
1063   return nasal::Ghost<T>::fromNasal(c, ref);
1064 }
1065
1066 /**
1067  * Convert any pointer to a SGReference based object to a ghost.
1068  */
1069 template<class T>
1070 typename boost::enable_if<boost::is_base_of<SGReferenced, T>, naRef>::type
1071 to_nasal_helper(naContext c, T* ptr)
1072 {
1073   return nasal::Ghost<SGSharedPtr<T> >::create(c, SGSharedPtr<T>(ptr));
1074 }
1075
1076 /**
1077  * Convert nasal ghosts/hashes to pointer (of a SGReference based ghost).
1078  */
1079 template<class T>
1080 typename boost::enable_if<
1081   boost::is_base_of<SGReferenced, typename boost::remove_pointer<T>::type>,
1082   T
1083 >::type
1084 from_nasal_helper(naContext c, naRef ref, const T*)
1085 {
1086   typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
1087   return nasal::Ghost<TypeRef>::fromNasal(c, ref).release();
1088 }
1089
1090 #endif /* SG_NASAL_GHOST_HXX_ */