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