]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/cppbind/Ghost.hxx
cppbind: add to_nasal_helper for enums.
[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
25 #include <simgear/debug/logstream.hxx>
26
27 #include <boost/bind.hpp>
28 #include <boost/call_traits.hpp>
29 #include <boost/function.hpp>
30 #include <boost/lambda/lambda.hpp>
31 #include <boost/mpl/has_xxx.hpp>
32 #include <boost/preprocessor/iteration/iterate.hpp>
33 #include <boost/shared_ptr.hpp>
34 #include <boost/utility/enable_if.hpp>
35
36 #include <map>
37
38 template<class T>
39 inline T* get_pointer(boost::weak_ptr<T> const& p)
40 {
41   return p.lock().get();
42 }
43
44 /**
45  * Bindings between C++ and the Nasal scripting language
46  */
47 namespace nasal
48 {
49
50   namespace internal
51   {
52     /**
53      * Metadata for Ghost object types
54      */
55     class GhostMetadata
56     {
57       public:
58         /**
59          * Add a nasal base class to the ghost. Will be available in the ghosts
60          * parents array.
61          */
62         void addNasalBase(const naRef& parent)
63         {
64           assert( naIsHash(parent) );
65           _parents.push_back(parent);
66         }
67
68         bool isBaseOf(naGhostType* ghost_type) const
69         {
70           if( ghost_type == &_ghost_type )
71             return true;
72
73           for( DerivedList::const_iterator derived = _derived_classes.begin();
74                                            derived != _derived_classes.end();
75                                          ++derived )
76           {
77             if( (*derived)->isBaseOf(ghost_type) )
78               return true;
79           }
80
81           return false;
82         }
83
84       protected:
85
86         typedef std::vector<const GhostMetadata*> DerivedList;
87
88         const std::string   _name;
89         naGhostType         _ghost_type;
90         DerivedList         _derived_classes;
91         std::vector<naRef>  _parents;
92
93         explicit GhostMetadata(const std::string& name):
94           _name(name)
95         {
96
97         }
98
99         void addDerived(const GhostMetadata* derived)
100         {
101           assert(derived);
102           _derived_classes.push_back(derived);
103
104           SG_LOG
105           (
106             SG_NASAL,
107             SG_INFO,
108             "Ghost::addDerived: " <<_ghost_type.name << " -> " << derived->_name
109           );
110         }
111
112         naRef getParents(naContext c)
113         {
114           return nasal::to_nasal(c, _parents);
115         }
116     };
117
118     /**
119      * Hold callable method and convert to Nasal function if required.
120      */
121     class MethodHolder
122     {
123       public:
124         virtual ~MethodHolder() {}
125         virtual naRef get_naRef(naContext c) = 0;
126     };
127
128     BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
129
130     template<class T>
131     struct reduced_type
132     {
133       typedef typename boost::remove_cv<
134         typename boost::remove_reference<T>::type
135       >::type type;
136     };
137
138     template<class T1, class T2>
139     struct reduced_is_same:
140       public boost::is_same<typename reduced_type<T1>::type, T2>
141     {};
142   }
143
144   /**
145    * Class for exposing C++ objects to Nasal
146    *
147    * @code{cpp}
148    * // Example class to be exposed to Nasal
149    * class MyClass
150    * {
151    *   public:
152    *     void setX(int x);
153    *     int getX() const;
154    *
155    *     int myMember();
156    *     void doSomethingElse(const nasal::CallContext& ctx);
157    * }
158    * typedef boost::shared_ptr<MyClass> MyClassPtr;
159    *
160    * std::string myOtherFreeMember(int num);
161    *
162    * void exposeClasses()
163    * {
164    *   // Register a nasal ghost type for MyClass. This needs to be done only
165    *   // once before creating the first ghost instance. The exposed class needs
166    *   // to be wrapped inside a shared pointer, eg. boost::shared_ptr.
167    *   Ghost<MyClassPtr>::init("MyClass")
168    *     // Members can be exposed by getters and setters
169    *     .member("x", &MyClass::getX, &MyClass::setX)
170    *     // For readonly variables only pass a getter
171    *     .member("x_readonly", &MyClass::getX)
172    *     // It is also possible to expose writeonly members
173    *     .member("x_writeonly", &MyClass::setX)
174    *     // Methods can be nearly anything callable and accepting a reference
175    *     // to an instance of the class type. (member functions, free functions
176    *     // and anything else bindable using boost::function and boost::bind)
177    *     .method("myMember", &MyClass::myMember)
178    *     .method("doSomething", &MyClass::doSomethingElse)
179    *     .method("other", &myOtherFreeMember);
180    * }
181    * @endcode
182    */
183   template<class T>
184   class Ghost:
185     public internal::GhostMetadata
186   {
187       BOOST_STATIC_ASSERT( internal::has_element_type<T>::value );
188
189     public:
190       typedef typename T::element_type                              raw_type;
191       typedef T                                                     pointer;
192       typedef naRef (raw_type::*member_func_t)(const CallContext&);
193       typedef naRef (*free_func_t)(raw_type&, const CallContext&);
194       typedef boost::function<naRef(naContext, raw_type&)>          getter_t;
195       typedef boost::function<void(naContext, raw_type&, naRef)>    setter_t;
196       typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
197       typedef boost::shared_ptr<internal::MethodHolder> MethodHolderPtr;
198
199       class MethodHolder:
200         public internal::MethodHolder
201       {
202         public:
203           MethodHolder():
204             _naRef(naNil())
205           {}
206
207           explicit MethodHolder(const method_t& method):
208             _method(method),
209             _naRef(naNil())
210           {}
211
212           virtual naRef get_naRef(naContext c)
213           {
214             if( naIsNil(_naRef) )
215             {
216               _naRef = naNewFunc(c, naNewCCodeU(c, &MethodHolder::call, this));
217               naSave(c, _naRef);
218             }
219             return _naRef;
220           }
221
222         protected:
223           method_t  _method;
224           naRef     _naRef;
225
226           static naRef call( naContext c,
227                              naRef me,
228                              int argc,
229                              naRef* args,
230                              void* user_data )
231           {
232             MethodHolder* holder = static_cast<MethodHolder*>(user_data);
233             if( !holder )
234               naRuntimeError(c, "invalid method holder!");
235
236             try
237             {
238               return holder->_method
239               (
240                 requireObject(c, me),
241                 CallContext(c, argc, args)
242               );
243             }
244             catch(const std::exception& ex)
245             {
246               naRuntimeError(c, "Fatal error in method call: %s", ex.what());
247             }
248             catch(...)
249             {
250               naRuntimeError(c, "Unknown exception in method call.");
251             }
252
253             return naNil();
254           }
255       };
256
257       /**
258        * A ghost member. Can consist either of getter and/or setter functions
259        * for exposing a data variable or a single callable function.
260        */
261       struct member_t
262       {
263         member_t()
264         {}
265
266         member_t( const getter_t& getter,
267                   const setter_t& setter,
268                   const MethodHolderPtr& func = MethodHolderPtr() ):
269           getter( getter ),
270           setter( setter ),
271           func( func )
272         {}
273
274         explicit member_t(const MethodHolderPtr& func):
275           func( func )
276         {}
277
278         getter_t        getter;
279         setter_t        setter;
280         MethodHolderPtr func;
281       };
282
283       typedef std::map<std::string, member_t> MemberMap;
284
285       /**
286        * Register a new ghost type.
287        *
288        * @note Only intialize each ghost type once!
289        *
290        * @param name    Descriptive name of the ghost type.
291        */
292       static Ghost& init(const std::string& name)
293       {
294         assert( !getSingletonPtr() );
295
296         getSingletonHolder().reset( new Ghost(name) );
297         return *getSingletonPtr();
298       }
299
300       /**
301        * Check whether ghost type has already been initialized.
302        */
303       static bool isInit()
304       {
305         return getSingletonPtr();
306       }
307
308       /**
309        * Register a base class for this ghost. The base class needs to be
310        * registers on its own before it can be used as base class.
311        *
312        * @tparam BaseGhost  Type of base class already wrapped into Ghost class
313        *                    (Ghost<BasePtr>)
314        *
315        * @code{cpp}
316        * Ghost<MyBasePtr>::init("MyBase");
317        * Ghost<MyClassPtr>::init("MyClass")
318        *   .bases<Ghost<MyBasePtr> >();
319        * @endcode
320        */
321       template<class BaseGhost>
322       typename boost::enable_if
323         <
324           boost::is_base_of<GhostMetadata, BaseGhost>,
325           Ghost
326         >::type&
327       bases()
328       {
329         BOOST_STATIC_ASSERT
330         ((
331           boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
332         ));
333
334         BaseGhost* base = BaseGhost::getSingletonPtr();
335         base->addDerived
336         (
337           this,
338           // Both ways of retrieving the address of a static member function
339           // should be legal but not all compilers know this.
340           // g++-4.4.7+ has been tested to work with both versions
341 #if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407
342           // The old version of g++ used on Jenkins (16.11.2012) only compiles
343           // this version.
344           &getTypeFor<BaseGhost>
345 #else
346           // VS (2008, 2010, ... ?) only allow this version.
347           &Ghost::getTypeFor<BaseGhost>
348 #endif
349         );
350
351         // Replace any getter that is not available in the current class.
352         // TODO check if this is the correct behavior of function overriding
353         for( typename BaseGhost::MemberMap::const_iterator member =
354                base->_members.begin();
355                member != base->_members.end();
356              ++member )
357         {
358           if( _members.find(member->first) == _members.end() )
359             _members[member->first] = member_t
360             (
361               member->second.getter,
362               member->second.setter,
363               member->second.func
364             );
365         }
366
367         return *this;
368       }
369
370       /**
371        * Register a base class for this ghost. The base class needs to be
372        * registers on its own before it can be used as base class.
373        *
374        * @tparam Base   Type of base class (Base as used in Ghost<BasePtr>)
375        *
376        * @code{cpp}
377        * Ghost<MyBasePtr>::init("MyBase");
378        * Ghost<MyClassPtr>::init("MyClass")
379        *   .bases<MyBasePtr>();
380        * @endcode
381        */
382       template<class Base>
383       typename boost::disable_if
384         <
385           boost::is_base_of<GhostMetadata, Base>,
386           Ghost
387         >::type&
388       bases()
389       {
390         BOOST_STATIC_ASSERT
391         ((
392           boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
393         ));
394
395         return bases< Ghost<Base> >();
396       }
397
398       /**
399        * Register an existing Nasal class/hash as base class for this ghost.
400        *
401        * @param parent  Nasal hash/class
402        */
403       Ghost& bases(const naRef& parent)
404       {
405         addNasalBase(parent);
406         return *this;
407       }
408
409       /**
410        * Register a member variable by passing a getter and/or setter method.
411        *
412        * @param field   Name of member
413        * @param getter  Getter for variable
414        * @param setter  Setter for variable (Pass 0 to prevent write access)
415        *
416        */
417       template<class Ret, class Param>
418       Ghost& member( const std::string& field,
419                      Ret (raw_type::*getter)() const,
420                      void (raw_type::*setter)(Param) )
421       {
422         return member(field, to_getter(getter), to_setter(setter));
423       }
424
425       /**
426        * Register a read only member variable.
427        *
428        * @param field   Name of member
429        * @param getter  Getter for variable
430        */
431       template<class Ret>
432       Ghost& member( const std::string& field,
433                      Ret (raw_type::*getter)() const )
434       {
435         return member(field, to_getter(getter), setter_t());
436       }
437
438       /**
439        * Register a write only member variable.
440        *
441        * @param field   Name of member
442        * @param setter  Setter for variable
443        */
444       template<class Var>
445       Ghost& member( const std::string& field,
446                      void (raw_type::*setter)(Var) )
447       {
448         return member(field, getter_t(), to_setter(setter));
449       }
450
451       /**
452        * Register a member variable by passing a getter and/or setter method.
453        *
454        * @param field   Name of member
455        * @param getter  Getter for variable
456        * @param setter  Setter for variable (Pass empty to prevent write access)
457        *
458        */
459       Ghost& member( const std::string& field,
460                      const getter_t& getter,
461                      const setter_t& setter = setter_t() )
462       {
463         if( !getter.empty() || !setter.empty() )
464           _members[field] = member_t(getter, setter);
465         else
466           SG_LOG
467           (
468             SG_NASAL,
469             SG_WARN,
470             "Member '" << field << "' requires a getter or setter"
471           );
472         return *this;
473       }
474
475       /**
476        * Register anything that accepts an object instance and a
477        * nasal::CallContext and returns naRef as method.
478        *
479        * @code{cpp}
480        * class MyClass
481        * {
482        *   public:
483        *     naRef myMethod(const nasal::CallContext& ctx);
484        * }
485        *
486        * Ghost<MyClassPtr>::init("Test")
487        *   .method("myMethod", &MyClass::myMethod);
488        * @endcode
489        */
490       Ghost& method(const std::string& name, const method_t& func)
491       {
492         _members[name].func.reset( new MethodHolder(func) );
493         return *this;
494       }
495
496       /**
497        * Register anything that accepts an object instance and a
498        * nasal::CallContext whith automatic conversion of the return type to
499        * Nasal.
500        *
501        * @code{cpp}
502        * class MyClass;
503        * void doIt(const MyClass& c, const nasal::CallContext& ctx);
504        *
505        * Ghost<MyClassPtr>::init("Test")
506        *   .method("doIt", &doIt);
507        * @endcode
508        */
509       template<class Ret>
510       Ghost& method
511       (
512         const std::string& name,
513         const boost::function<Ret (raw_type&, const CallContext&)>& func
514       )
515       {
516         return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
517       }
518
519 #define BOOST_PP_ITERATION_LIMITS (0, 9)
520 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
521 #include BOOST_PP_ITERATE()
522
523       // TODO use variadic template when supporting C++11
524       // TODO check if default constructor exists
525 //      static naRef create( naContext c )
526 //      {
527 //        return makeGhost(c, createInstance());
528 //      }
529
530       /**
531        * Create a Nasal instance of this ghost.
532        *
533        * @param c   Active Nasal context
534        * @param a1  Parameter used for creating new instance
535        */
536       template<class A1>
537       static naRef create( naContext c, const A1& a1 )
538       {
539         return makeGhost(c, createInstance(a1));
540       }
541
542       /**
543        * Nasal callback for creating a new instance of this ghost.
544        */
545       static naRef f_create(naContext c, naRef me, int argc, naRef* args)
546       {
547         return create(c);
548       }
549
550       static bool isBaseOf(naGhostType* ghost_type)
551       {
552         if( !ghost_type )
553           return false;
554
555         return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type);
556       }
557
558       static bool isBaseOf(naRef obj)
559       {
560         return isBaseOf( naGhost_type(obj) );
561       }
562
563       /**
564        * Convert Nasal object to C++ object. To get a valid object the passed
565        * Nasal objects has to be derived class of the target class (Either
566        * derived in C++ or in Nasal using a 'parents' vector)
567        */
568       static pointer fromNasal(naContext c, naRef me)
569       {
570         // Check if it's a ghost and if it can be converted
571         if( isBaseOf( naGhost_type(me) ) )
572           return getPtr( naGhost_ptr(me) );
573
574         // Now if it is derived from a ghost (hash with ghost in parent vector)
575         else if( naIsHash(me) )
576         {
577           naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
578           if( !naIsVector(na_parents) )
579           {
580             SG_LOG(SG_NASAL, SG_DEBUG, "Missing 'parents' vector for ghost");
581             return pointer();
582           }
583
584           typedef std::vector<naRef> naRefs;
585           naRefs parents = from_nasal<naRefs>(c, na_parents);
586           for( naRefs::const_iterator parent = parents.begin();
587                                       parent != parents.end();
588                                     ++parent )
589           {
590             pointer ptr = fromNasal(c, *parent);
591             if( get_pointer(ptr) )
592               return ptr;
593           }
594         }
595
596         return pointer();
597       }
598
599     private:
600
601       template<class>
602       friend class Ghost;
603
604       typedef naGhostType* (*type_checker_t)(const raw_type*);
605       typedef std::vector<type_checker_t> DerivedList;
606       DerivedList _derived_types;
607
608       /**
609        * Create a shared pointer on the heap to handle the reference counting
610        * for the passed shared pointer while it is used in Nasal space.
611        */
612       static pointer* createInstance(const pointer& ptr)
613       {
614         return get_pointer(ptr) ? new pointer(ptr) : 0;
615       }
616
617       static pointer getPtr(void* ptr)
618       {
619         if( ptr )
620           return *static_cast<pointer*>(ptr);
621         else
622           return pointer();
623       }
624
625       static raw_type* getRawPtr(void* ptr)
626       {
627         if( ptr )
628           return get_pointer(*static_cast<pointer*>(ptr));
629         else
630           return 0;
631       }
632
633       static raw_type* getRawPtr(const pointer& ptr)
634       {
635         return get_pointer(ptr);
636       }
637
638       void addDerived( const internal::GhostMetadata* derived_meta,
639                        const type_checker_t& derived_info )
640       {
641         GhostMetadata::addDerived(derived_meta);
642         _derived_types.push_back(derived_info);
643       }
644
645       template<class BaseGhost>
646       static
647       typename boost::enable_if
648         < boost::is_polymorphic<typename BaseGhost::raw_type>,
649           naGhostType*
650         >::type
651       getTypeFor(const typename BaseGhost::raw_type* base)
652       {
653         // Check first if passed pointer can by converted to instance of class
654         // this ghost wraps.
655         if(   !boost::is_same
656                  < typename BaseGhost::raw_type,
657                    typename Ghost::raw_type
658                  >::value
659             && dynamic_cast<const typename Ghost::raw_type*>(base) != base )
660           return 0;
661
662         // Now check if we can further downcast to one of our derived classes.
663         for( typename DerivedList::reverse_iterator
664                derived = getSingletonPtr()->_derived_types.rbegin();
665                derived != getSingletonPtr()->_derived_types.rend();
666              ++derived )
667         {
668           naGhostType* ghost_type =
669             (*derived)( static_cast<const typename Ghost::raw_type*>(base) );
670           if( ghost_type )
671             return ghost_type;
672         }
673
674         // If base is not an instance of any derived class, this class has to
675         // be the dynamic type.
676         return &getSingletonPtr()->_ghost_type;
677       }
678
679       template<class BaseGhost>
680       static
681       typename boost::disable_if
682         < boost::is_polymorphic<typename BaseGhost::raw_type>,
683           naGhostType*
684         >::type
685       getTypeFor(const typename BaseGhost::raw_type* base)
686       {
687         // For non polymorphic classes there is no possibility to get the actual
688         // dynamic type, therefore we can only use its static type.
689         return &BaseGhost::getSingletonPtr()->_ghost_type;
690       }
691
692       static Ghost* getSingletonPtr()
693       {
694         return getSingletonHolder().get();
695       }
696
697       static raw_type& requireObject(naContext c, naRef me)
698       {
699         raw_type* obj = getRawPtr( fromNasal(c, me) );
700         naGhostType* ghost_type = naGhost_type(me);
701
702         if( !obj )
703           naRuntimeError
704           (
705             c,
706             "method called on object of wrong type: is '%s' expected '%s'",
707             ghost_type ? ghost_type->name : "unknown",
708             getSingletonPtr()->_ghost_type.name
709           );
710
711         return *obj;
712       }
713
714       template<class Ret>
715       getter_t to_getter(Ret (raw_type::*getter)() const)
716       {
717         typedef typename boost::call_traits<Ret>::param_type param_type;
718         naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
719
720         // Getter signature: naRef(naContext, raw_type&)
721         return boost::bind
722         (
723           to_nasal_,
724           _1,
725           boost::bind(getter, _2)
726         );
727       }
728
729       template<class Param>
730       setter_t to_setter(void (raw_type::*setter)(Param))
731       {
732         // Setter signature: void(naContext, raw_type&, naRef)
733         return boost::bind
734         (
735           setter,
736           _2,
737           boost::bind(from_nasal_ptr<Param>::get(), _1, _3)
738         );
739       }
740
741
742       /**
743        * Invoke a method which returns a value and convert it to Nasal.
744        */
745       template<class Ret>
746       static
747       typename boost::disable_if<boost::is_void<Ret>, naRef>::type
748       method_invoker
749       (
750         const boost::function<Ret (raw_type&, const CallContext&)>& func,
751         raw_type& obj,
752         const CallContext& ctx
753       )
754       {
755         return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
756       };
757
758       /**
759        * Invoke a method which returns void and "convert" it to nil.
760        */
761       template<class Ret>
762       static
763       typename boost::enable_if<boost::is_void<Ret>, naRef>::type
764       method_invoker
765       (
766         const boost::function<Ret (raw_type&, const CallContext&)>& func,
767         raw_type& obj,
768         const CallContext& ctx
769       )
770       {
771         func(obj, ctx);
772         return naNil();
773       };
774
775       /**
776        * Extract argument by index from nasal::CallContext and convert to given
777        * type.
778        */
779       template<class Arg>
780       static
781       typename boost::disable_if<
782         internal::reduced_is_same<Arg, CallContext>,
783         typename from_nasal_ptr<Arg>::return_type
784       >::type
785       arg_from_nasal(const CallContext& ctx, size_t index)
786       {
787         return ctx.requireArg<Arg>(index);
788       };
789
790       /**
791        * Specialization to pass through nasal::CallContext.
792        */
793       template<class Arg>
794       static
795       typename boost::enable_if<
796         internal::reduced_is_same<Arg, CallContext>,
797         typename from_nasal_ptr<Arg>::return_type
798       >::type
799       arg_from_nasal(const CallContext& ctx, size_t)
800       {
801         // Either const CallContext& or CallContext, non-const reference
802         // does not make sense.
803         BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
804         return ctx;
805       };
806
807       typedef std::auto_ptr<Ghost> GhostPtr;
808       MemberMap _members;
809
810       explicit Ghost(const std::string& name):
811         GhostMetadata( name )
812       {
813         _ghost_type.destroy = &destroyGhost;
814         _ghost_type.name = _name.c_str();
815         _ghost_type.get_member = &getMember;
816         _ghost_type.set_member = &setMember;
817       }
818
819       static GhostPtr& getSingletonHolder()
820       {
821         static GhostPtr instance;
822         return instance;
823       }
824
825       static naRef makeGhost(naContext c, void *ptr)
826       {
827         if( getRawPtr(ptr) )
828         {
829           // We are wrapping shared pointers to already existing objects which
830           // will then be hold be a new shared pointer. We therefore have to
831           // check for the dynamic type of the object as it might differ from
832           // the passed static type.
833           naGhostType* ghost_type = getTypeFor<Ghost>( getRawPtr(ptr) );
834
835           if( ghost_type )
836             return naNewGhost2(c, ghost_type, ptr);
837         }
838
839         destroyGhost(ptr);
840         return naNil();
841       }
842
843       static void destroyGhost(void *ptr)
844       {
845         delete static_cast<pointer*>(ptr);
846       }
847
848       /**
849        * Callback for retrieving a ghost member.
850        */
851       static const char* getMember(naContext c, void* g, naRef key, naRef* out)
852       {
853         const std::string key_str = nasal::from_nasal<std::string>(c, key);
854         if( key_str == "parents" )
855         {
856           if( getSingletonPtr()->_parents.empty() )
857             return 0;
858
859           *out = getSingletonPtr()->getParents(c);
860           return "";
861         }
862
863         typename MemberMap::iterator member =
864           getSingletonPtr()->_members.find(key_str);
865
866         if( member == getSingletonPtr()->_members.end() )
867           return 0;
868
869         if( member->second.func )
870           *out = member->second.func->get_naRef(c);
871         else if( !member->second.getter.empty() )
872           *out = member->second.getter(c, *getRawPtr(g));
873         else
874           return "Read-protected member";
875
876         return "";
877       }
878
879       /**
880        * Callback for writing to a ghost member.
881        */
882       static void setMember(naContext c, void* g, naRef field, naRef val)
883       {
884         const std::string key = nasal::from_nasal<std::string>(c, field);
885         typename MemberMap::iterator member =
886           getSingletonPtr()->_members.find(key);
887
888         if( member == getSingletonPtr()->_members.end() )
889           naRuntimeError(c, "ghost: No such member: %s", key.c_str());
890         else if( member->second.setter.empty() )
891           naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
892         else if( member->second.func )
893           naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
894
895         member->second.setter(c, *getRawPtr(g), val);
896       }
897   };
898
899 } // namespace nasal
900
901 /**
902  * Convert every shared pointer to a ghost.
903  */
904 // Needs to be outside any namespace to mark ADL work
905 template<class T>
906 typename boost::enable_if<
907   nasal::internal::has_element_type<
908     typename nasal::internal::reduced_type<T>::type
909   >,
910   naRef
911 >::type
912 to_nasal_helper(naContext c, T ptr)
913 {
914   return nasal::Ghost<T>::create(c, ptr);
915 }
916
917 /**
918  * Convert nasal ghosts/hashes to shared pointer (of a ghost)
919  */
920 template<class T>
921 typename boost::enable_if<
922   nasal::internal::has_element_type<
923     typename nasal::internal::reduced_type<T>::type
924   >,
925   T
926 >::type
927 from_nasal_helper(naContext c, naRef ref, const T*)
928 {
929   return nasal::Ghost<T>::fromNasal(c, ref);
930 }
931
932 #endif /* SG_NASAL_GHOST_HXX_ */