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