]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/cppbind/Ghost.hxx
7b0d7fbeed6d9ec764eddf564602fe72088b5d04
[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 namespace osg
54 {
55   template<class T>
56   inline T* get_pointer(observer_ptr<T> const& p)
57   {
58     ref_ptr<T> ref;
59     p.lock(ref);
60     return ref.get();
61   }
62 }
63
64 template<class T>
65 inline typename boost::enable_if<
66   boost::is_pointer<T>,
67   T
68 >::type
69 get_pointer(T ptr)
70 {
71   return ptr;
72 }
73
74 // Both ways of retrieving the address of a static member function
75 // should be legal but not all compilers know this.
76 // g++-4.4.7+ has been tested to work with both versions
77 #if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407
78   // The old version of g++ used on Jenkins (16.11.2012) only compiles
79   // this version.
80 # define SG_GET_TEMPLATE_MEMBER(type, member) &member
81
82   // With old g++ on Jenkins (21.07.2014), ADL for boost::static_pointer_cast
83   // does not work.
84   using boost::static_pointer_cast;
85 #else
86   // VS (2008, 2010, ... ?) only allow this version.
87 # define SG_GET_TEMPLATE_MEMBER(type, member) &type::template member
88 #endif
89
90 /**
91  * Bindings between C++ and the Nasal scripting language
92  */
93 namespace nasal
94 {
95   namespace internal
96   {
97     /**
98      * Metadata for Ghost object types
99      */
100     class GhostMetadata
101     {
102       public:
103         typedef void(*Deleter)(void*);
104         typedef std::vector<std::pair<Deleter, void*> > DestroyList;
105
106         static DestroyList _destroy_list;
107
108         /**
109          * Add a nasal base class to the ghost. Will be available in the ghosts
110          * parents array.
111          */
112         void addNasalBase(const naRef& parent);
113
114         bool isInstance(naGhostType* ghost_type, bool& is_weak) const;
115
116       protected:
117
118         const std::string   _name_strong,
119                             _name_weak;
120         const naGhostType  *_ghost_type_strong_ptr,
121                            *_ghost_type_weak_ptr;
122         std::vector<naRef>  _parents;
123
124         GhostMetadata( const std::string& name,
125                        const naGhostType* ghost_type_strong,
126                        const naGhostType* ghost_type_weak );
127
128         void addDerived(const GhostMetadata* derived);
129
130         naRef getParents(naContext c);
131     };
132
133     /**
134      * Hold callable method and convert to Nasal function if required.
135      */
136     class MethodHolder:
137       public SGWeakReferenced
138     {
139       public:
140         virtual ~MethodHolder() {}
141
142         naRef get_naRef(naContext c)
143         {
144           if( !_obj.valid() )
145             _obj.reset(createNasalObject(c));
146           return _obj.get_naRef();
147         }
148
149       protected:
150         ObjectHolder<> _obj;
151
152         virtual naRef createNasalObject(naContext c) = 0;
153     };
154
155     BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
156
157     template<class T>
158     struct reduced_type
159     {
160       typedef typename boost::remove_cv<
161         typename boost::remove_reference<T>::type
162       >::type type;
163     };
164
165     template<class T1, class T2>
166     struct reduced_is_same:
167       public boost::is_same<typename reduced_type<T1>::type, T2>
168     {};
169   }
170
171   /** @brief Destroy all ghost queued for deletion.
172    *
173    * This needs can not be done directly during garbage collection, as
174    * destructors may execute Nasal code which requires creating new Nasal
175    * contexts. Creating a Nasal context during garbage collection is not
176    * possible and leads to a dead lock.
177    */
178   void ghostProcessDestroyList();
179
180   typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
181   typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
182
183   // Dummy template to create shorter and easy to understand compile errors if
184   // trying to wrap the wrong type as a Ghost.
185   template<class T, class Enable = void>
186   class Ghost
187   {
188     public:
189       BOOST_STATIC_ASSERT(("Ghost can only wrap shared pointer!"
190         && is_strong_ref<T>::value
191       ));
192
193       static Ghost& init(const std::string& name);
194       static bool isInit();
195   };
196
197   /**
198    * Class for exposing C++ objects to Nasal
199    *
200    * @code{cpp}
201    * // Example class to be exposed to Nasal
202    * class MyClass
203    * {
204    *   public:
205    *     void setX(int x);
206    *     int getX() const;
207    *
208    *     int myMember();
209    *     void doSomethingElse(const nasal::CallContext& ctx);
210    * }
211    * typedef boost::shared_ptr<MyClass> MyClassPtr;
212    *
213    * std::string myOtherFreeMember(int num);
214    *
215    * void exposeClasses()
216    * {
217    *   // Register a nasal ghost type for MyClass. This needs to be done only
218    *   // once before creating the first ghost instance. The exposed class needs
219    *   // to be wrapped inside a shared pointer, eg. boost::shared_ptr.
220    *   Ghost<MyClassPtr>::init("MyClass")
221    *     // Members can be exposed by getters and setters
222    *     .member("x", &MyClass::getX, &MyClass::setX)
223    *     // For readonly variables only pass a getter
224    *     .member("x_readonly", &MyClass::getX)
225    *     // It is also possible to expose writeonly members
226    *     .member("x_writeonly", &MyClass::setX)
227    *     // Methods can be nearly anything callable and accepting a reference
228    *     // to an instance of the class type. (member functions, free functions
229    *     // and anything else bindable using boost::function and boost::bind)
230    *     .method("myMember", &MyClass::myMember)
231    *     .method("doSomething", &MyClass::doSomethingElse)
232    *     .method("other", &myOtherFreeMember);
233    * }
234    * @endcode
235    */
236   template<class T>
237   class Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>:
238     public internal::GhostMetadata
239   {
240       // Shared pointer required for Ghost (no weak pointer!)
241       BOOST_STATIC_ASSERT((is_strong_ref<T>::value));
242
243     public:
244       typedef typename T::element_type                              raw_type;
245       typedef typename shared_ptr_traits<T>::strong_ref             strong_ref;
246       typedef typename shared_ptr_traits<T>::weak_ref               weak_ref;
247       typedef naRef (raw_type::*member_func_t)(const CallContext&);
248       typedef naRef (*free_func_t)(raw_type&, const CallContext&);
249       typedef boost::function<naRef(raw_type&, naContext)>          getter_t;
250       typedef boost::function<void( raw_type&, naContext, naRef)>   setter_t;
251       typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
252       typedef boost::function<bool( raw_type&,
253                                     naContext,
254                                     const std::string&,
255                                     naRef& )>              fallback_getter_t;
256       typedef boost::function<bool( raw_type&,
257                                     naContext,
258                                     const std::string&,
259                                     naRef )>               fallback_setter_t;
260
261       class MethodHolder:
262         public internal::MethodHolder
263       {
264         public:
265           explicit MethodHolder(const method_t& method):
266             _method(method)
267           {}
268
269         protected:
270
271           typedef SGSharedPtr<MethodHolder> SharedPtr;
272           typedef SGWeakPtr<MethodHolder> WeakPtr;
273
274           method_t  _method;
275
276           virtual naRef createNasalObject(naContext c)
277           {
278             return naNewFunc
279             (
280               c,
281               naNewCCodeUD( c,
282                             &MethodHolder::call,
283                             new WeakPtr(this),
284                             &destroyHolder )
285             );
286           }
287
288           static void destroyHolder(void* user_data)
289           {
290             delete static_cast<WeakPtr*>(user_data);
291           }
292
293           static naRef call( naContext c,
294                              naRef me,
295                              int argc,
296                              naRef* args,
297                              void* user_data )
298           {
299             WeakPtr* holder_weak = static_cast<WeakPtr*>(user_data);
300             if( !holder_weak )
301               naRuntimeError(c, "invalid method holder!");
302
303             try
304             {
305               SharedPtr holder = holder_weak->lock();
306               if( !holder )
307                 throw std::runtime_error("holder has expired");
308
309               // Keep reference for duration of call to prevent expiring
310               // TODO not needed for strong referenced ghost
311               strong_ref ref = fromNasal(c, me);
312               if( !ref )
313               {
314                 naGhostType* ghost_type = naGhost_type(me);
315                 naRuntimeError
316                 (
317                   c,
318                   "method called on object of wrong type: "
319                   "is '%s' expected '%s'",
320                   naIsNil(me) ? "nil"
321                               : (ghost_type ? ghost_type->name : "unknown"),
322                   _ghost_type_strong.name
323                 );
324               }
325
326               return holder->_method
327               (
328                 *get_pointer(ref),
329                 CallContext(c, me, argc, args)
330               );
331             }
332             catch(const std::exception& ex)
333             {
334               naRuntimeError(c, "Fatal error in method call: %s", ex.what());
335             }
336             catch(...)
337             {
338               naRuntimeError(c, "Unknown exception in method call.");
339             }
340
341             return naNil();
342           }
343       };
344
345       /**
346        * A ghost member. Can consist either of getter and/or setter functions
347        * for exposing a data variable or a single callable function.
348        */
349       struct member_t
350       {
351         member_t()
352         {}
353
354         member_t( const getter_t& getter,
355                   const setter_t& setter,
356                   const MethodHolderPtr& func = MethodHolderPtr() ):
357           getter( getter ),
358           setter( setter ),
359           func( func )
360         {}
361
362         explicit member_t(const MethodHolderPtr& func):
363           func( func )
364         {}
365
366         getter_t        getter;
367         setter_t        setter;
368         MethodHolderPtr func;
369       };
370
371       typedef std::map<std::string, member_t> MemberMap;
372
373       /**
374        * Register a new ghost type.
375        *
376        * @note Only intialize each ghost type once!
377        *
378        * @param name    Descriptive name of the ghost type.
379        */
380       static Ghost& init(const std::string& name)
381       {
382         getSingletonHolder().reset( new Ghost(name) );
383         return *getSingletonPtr();
384       }
385
386       /**
387        * Check whether ghost type has already been initialized.
388        */
389       static bool isInit()
390       {
391         return getSingletonPtr();
392       }
393
394       /**
395        * Register a base class for this ghost. The base class needs to be
396        * registers on its own before it can be used as base class.
397        *
398        * @tparam BaseGhost  Type of base class already wrapped into Ghost class
399        *                    (Ghost<BasePtr>)
400        *
401        * @code{cpp}
402        * Ghost<MyBasePtr>::init("MyBase");
403        * Ghost<MyClassPtr>::init("MyClass")
404        *   .bases<Ghost<MyBasePtr> >();
405        * @endcode
406        */
407       template<class BaseGhost>
408       typename boost::enable_if
409         <
410           boost::is_base_of<GhostMetadata, BaseGhost>,
411           Ghost
412         >::type&
413       bases()
414       {
415         BOOST_STATIC_ASSERT
416         ((
417           boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
418         ));
419
420         typedef typename BaseGhost::strong_ref base_ref;
421
422         BaseGhost* base = BaseGhost::getSingletonPtr();
423         base->addDerived(
424           this,
425           SG_GET_TEMPLATE_MEMBER(Ghost, toNasal<BaseGhost>),
426           SG_GET_TEMPLATE_MEMBER(Ghost, fromNasalWithCast<base_ref>)
427         );
428
429         // Replace any getter that is not available in the current class.
430         // TODO check if this is the correct behavior of function overriding
431         for( typename BaseGhost::MemberMap::const_iterator member =
432                base->_members.begin();
433                member != base->_members.end();
434              ++member )
435         {
436           if( _members.find(member->first) == _members.end() )
437             _members[member->first] = member_t
438             (
439               member->second.getter,
440               member->second.setter,
441               member->second.func
442             );
443         }
444
445         if( !_fallback_setter )
446           _fallback_setter = base->_fallback_setter;
447         if( !_fallback_getter )
448           _fallback_getter = base->_fallback_getter;
449
450         return *this;
451       }
452
453       /**
454        * Register a base class for this ghost. The base class needs to be
455        * registers on its own before it can be used as base class.
456        *
457        * @tparam Base   Type of base class (Base as used in Ghost<BasePtr>)
458        *
459        * @code{cpp}
460        * Ghost<MyBasePtr>::init("MyBase");
461        * Ghost<MyClassPtr>::init("MyClass")
462        *   .bases<MyBasePtr>();
463        * @endcode
464        */
465       template<class Base>
466       typename boost::disable_if
467         <
468           boost::is_base_of<GhostMetadata, Base>,
469           Ghost
470         >::type&
471       bases()
472       {
473         BOOST_STATIC_ASSERT
474         ((
475           boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
476         ));
477
478         return bases< Ghost<Base> >();
479       }
480
481       /**
482        * Register an existing Nasal class/hash as base class for this ghost.
483        *
484        * @param parent  Nasal hash/class
485        */
486       Ghost& bases(const naRef& parent)
487       {
488         addNasalBase(parent);
489         return *this;
490       }
491
492       /**
493        * Register a member variable by passing a getter and/or setter method.
494        *
495        * @param field   Name of member
496        * @param getter  Getter for variable
497        * @param setter  Setter for variable (Pass 0 to prevent write access)
498        *
499        */
500       template<class Ret, class Param>
501       Ghost& member( const std::string& field,
502                      Ret (raw_type::*getter)() const,
503                      void (raw_type::*setter)(Param) )
504       {
505         return member(field, to_getter(getter), to_setter(setter));
506       }
507
508       template<class Param>
509       Ghost& member( const std::string& field,
510                      const getter_t& getter,
511                      void (raw_type::*setter)(Param) )
512       {
513         return member(field, getter, to_setter(setter));
514       }
515
516       template<class Ret>
517       Ghost& member( const std::string& field,
518                      Ret (raw_type::*getter)() const,
519                      const setter_t& setter )
520       {
521         return member(field, to_getter(getter), setter);
522       }
523
524       /**
525        * Register a read only member variable.
526        *
527        * @param field   Name of member
528        * @param getter  Getter for variable
529        */
530       template<class Ret>
531       Ghost& member( const std::string& field,
532                      Ret (raw_type::*getter)() const )
533       {
534         return member(field, to_getter(getter), setter_t());
535       }
536
537       Ghost& member( const std::string& field,
538                      naRef (*getter)(const raw_type&, naContext) )
539       {
540         return member(field, getter_t(getter), setter_t());
541       }
542
543       Ghost& member( const std::string& field,
544                      naRef (*getter)(raw_type&, naContext) )
545       {
546         return member(field, getter_t(getter), setter_t());
547       }
548
549       /**
550        * Register a write only member variable.
551        *
552        * @param field   Name of member
553        * @param setter  Setter for variable
554        */
555       template<class Var>
556       Ghost& member( const std::string& field,
557                      void (raw_type::*setter)(Var) )
558       {
559         return member(field, getter_t(), to_setter(setter));
560       }
561
562       Ghost& member( const std::string& field,
563                      void (*setter)(raw_type&, naContext, naRef) )
564       {
565         return member(field, getter_t(), setter_t(setter));
566       }
567
568       Ghost& member( const std::string& field,
569                      const setter_t& setter )
570       {
571         return member(field, getter_t(), setter);
572       }
573
574       /**
575        * Register a member variable by passing a getter and/or setter method.
576        *
577        * @param field   Name of member
578        * @param getter  Getter for variable
579        * @param setter  Setter for variable (Pass empty to prevent write access)
580        *
581        */
582       Ghost& member( const std::string& field,
583                      const getter_t& getter,
584                      const setter_t& setter = setter_t() )
585       {
586         if( !getter.empty() || !setter.empty() )
587           _members[field] = member_t(getter, setter);
588         else
589           SG_LOG
590           (
591             SG_NASAL,
592             SG_WARN,
593             "Member '" << field << "' requires a getter or setter"
594           );
595         return *this;
596       }
597
598       /**
599        * Register a function which is called upon retrieving an unknown member
600        * of this ghost.
601        */
602       Ghost& _get(const fallback_getter_t& getter)
603       {
604         _fallback_getter = getter;
605         return *this;
606       }
607
608       /**
609        * Register a function which is called upon retrieving an unknown member
610        * of this ghost, and convert it to the given @a Param type.
611        */
612       template<class Param>
613       Ghost& _get( const boost::function<bool ( raw_type&,
614                                                 const std::string&,
615                                                 Param& )>& getter )
616       {
617         return _get(boost::bind(
618           convert_param_invoker<Param>, getter, _1, _2, _3, _4
619         ));
620       }
621
622       /**
623        * Register a method which is called upon retrieving an unknown member of
624        * this ghost.
625        *
626        * @code{cpp}
627        * class MyClass
628        * {
629        *   public:
630        *     bool getMember( const std::string& key,
631        *                     std::string& value_out ) const;
632        * }
633        *
634        * Ghost<MyClassPtr>::init("Test")
635        *   ._get(&MyClass::getMember);
636        * @endcode
637        */
638       template<class Param>
639       Ghost& _get(bool (raw_type::*getter)(const std::string&, Param&) const)
640       {
641         return _get(
642           boost::function<bool (raw_type&, const std::string&, Param&)>(getter)
643         );
644       }
645
646       /**
647        * Register a method which is called upon retrieving an unknown member of
648        * this ghost.
649        *
650        * @code{cpp}
651        * class MyClass
652        * {
653        *   public:
654        *     bool getMember( naContext c,
655        *                     const std::string& key,
656        *                     naRef& value_out );
657        * }
658        *
659        * Ghost<MyClassPtr>::init("Test")
660        *   ._get(&MyClass::getMember);
661        * @endcode
662        */
663       Ghost& _get(bool (raw_type::*getter)( naContext,
664                                             const std::string&,
665                                             naRef& ) const)
666       {
667         return _get( fallback_getter_t(getter) );
668       }
669
670       /**
671        * Register a function which is called upon setting an unknown member of
672        * this ghost.
673        */
674       Ghost& _set(const fallback_setter_t& setter)
675       {
676         _fallback_setter = setter;
677         return *this;
678       }
679
680       /**
681        * Register a function which is called upon setting an unknown member of
682        * this ghost, and convert it to the given @a Param type.
683        */
684       template<class Param>
685       Ghost& _set(const boost::function<bool ( raw_type&,
686                                                const std::string&,
687                                                Param )>& setter)
688       {
689         // Setter signature: bool( raw_type&,
690         //                         naContext,
691         //                         const std::string&,
692         //                         naRef )
693         return _set(boost::bind(
694           setter,
695           _1,
696           _3,
697           boost::bind(from_nasal_ptr<Param>::get(), _2, _4)
698         ));
699       }
700
701       /**
702        * Register a method which is called upon setting an unknown member of
703        * this ghost.
704        *
705        * @code{cpp}
706        * class MyClass
707        * {
708        *   public:
709        *     bool setMember( const std::string& key,
710        *                     const std::string& value );
711        * }
712        *
713        * Ghost<MyClassPtr>::init("Test")
714        *   ._set(&MyClass::setMember);
715        * @endcode
716        */
717       template<class Param>
718       Ghost& _set(bool (raw_type::*setter)(const std::string&, Param))
719       {
720         return _set(
721           boost::function<bool (raw_type&, const std::string&, Param)>(setter)
722         );
723       }
724
725       /**
726        * Register a method which is called upon setting an unknown member of
727        * this ghost.
728        *
729        * @code{cpp}
730        * class MyClass
731        * {
732        *   public:
733        *     bool setMember( naContext c,
734        *                     const std::string& key,
735        *                     naRef value );
736        * }
737        *
738        * Ghost<MyClassPtr>::init("Test")
739        *   ._set(&MyClass::setMember);
740        * @endcode
741        */
742       Ghost& _set(bool (raw_type::*setter)( naContext,
743                                             const std::string&,
744                                             naRef ))
745       {
746         return _set( fallback_setter_t(setter) );
747       }
748
749       /**
750        * Register anything that accepts an object instance and a
751        * nasal::CallContext and returns naRef as method.
752        *
753        * @code{cpp}
754        * class MyClass
755        * {
756        *   public:
757        *     naRef myMethod(const nasal::CallContext& ctx);
758        * }
759        *
760        * Ghost<MyClassPtr>::init("Test")
761        *   .method("myMethod", &MyClass::myMethod);
762        * @endcode
763        */
764       Ghost& method(const std::string& name, const method_t& func)
765       {
766         _members[name].func = new MethodHolder(func);
767         return *this;
768       }
769
770       /**
771        * Register anything that accepts an object instance and a
772        * nasal::CallContext whith automatic conversion of the return type to
773        * Nasal.
774        *
775        * @code{cpp}
776        * class MyClass;
777        * void doIt(const MyClass& c, const nasal::CallContext& ctx);
778        *
779        * Ghost<MyClassPtr>::init("Test")
780        *   .method("doIt", &doIt);
781        * @endcode
782        */
783       template<class Ret>
784       Ghost& method
785       (
786         const std::string& name,
787         const boost::function<Ret (raw_type&, const CallContext&)>& func
788       )
789       {
790         return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
791       }
792
793       // Build dependency for CMake, gcc, etc.
794 #define SG_DONT_DO_ANYTHING
795 # include <simgear/nasal/cppbind/detail/functor_templates.hxx>
796 #undef SG_DONT_DO_ANYTHING
797
798 #define BOOST_PP_ITERATION_LIMITS (0, 9)
799 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
800 #include BOOST_PP_ITERATE()
801
802       /**
803        * Create a shared pointer on the heap to handle the reference counting
804        * for the passed shared pointer while it is used in Nasal space.
805        */
806       template<class RefType>
807       static
808       typename boost::enable_if_c<
809            boost::is_same<RefType, strong_ref>::value
810         || boost::is_same<RefType, weak_ref>::value,
811         naRef
812       >::type
813       makeGhost(naContext c, RefType const& ref_ptr)
814       {
815         strong_ref ref(ref_ptr);
816         raw_type* ptr = get_pointer(ref);
817         if( !ptr )
818           return naNil();
819
820         // We are wrapping shared pointers to already existing objects which
821         // will then be hold be a new shared pointer. We therefore have to
822         // check for the dynamic type of the object as it might differ from
823         // the passed static type.
824         return toNasal<Ghost>(
825           c,
826           ref,
827           shared_ptr_traits<RefType>::is_strong::value
828         );
829       }
830
831       /**
832        * Convert Nasal object to C++ object. To get a valid object the passed
833        * Nasal objects has to be derived class of the target class (Either
834        * derived in C++ or in Nasal using a 'parents' vector)
835        */
836       static strong_ref fromNasal(naContext c, naRef me)
837       {
838         naGhostType* ghost_type = naGhost_type(me);
839         if( ghost_type )
840         {
841           // Check if we got an instance of this class
842           bool is_weak = false;
843           if( isInstance(ghost_type, is_weak) )
844           {
845             return is_weak ? getPtr<strong_ref, true>(naGhost_ptr(me))
846                            : getPtr<strong_ref, false>(naGhost_ptr(me));
847           }
848
849           // otherwise try the derived classes
850           for( typename DerivedList::reverse_iterator
851                  derived = getSingletonPtr()->_derived_types.rbegin();
852                  derived != getSingletonPtr()->_derived_types.rend();
853                ++derived )
854           {
855             strong_ref ref = (derived->from_nasal)(c, me);
856
857             if( get_pointer(ref) )
858               return ref;
859           }
860         }
861         else if( naIsHash(me) )
862         {
863           naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
864           if( !naIsVector(na_parents) )
865             return strong_ref();
866
867           typedef std::vector<naRef> naRefs;
868           naRefs parents = from_nasal<naRefs>(c, na_parents);
869           for( naRefs::const_iterator parent = parents.begin();
870                                       parent != parents.end();
871                                     ++parent )
872           {
873             strong_ref ref = fromNasal(c, *parent);
874             if( get_pointer(ref) )
875               return ref;
876           }
877         }
878
879         return strong_ref();
880       }
881
882     private:
883
884       template<class, class>
885       friend class Ghost;
886
887       static naGhostType _ghost_type_strong, //!< Stored as shared pointer
888                          _ghost_type_weak;   //!< Stored as weak shared pointer
889
890       typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool);
891       typedef strong_ref (*from_nasal_t)(naContext, naRef);
892       struct DerivedInfo
893       {
894         to_nasal_t to_nasal;
895         from_nasal_t from_nasal;
896
897         DerivedInfo( to_nasal_t to_nasal_func,
898                      from_nasal_t from_nasal_func ):
899           to_nasal(to_nasal_func),
900           from_nasal(from_nasal_func)
901         {}
902       };
903
904       typedef std::vector<DerivedInfo> DerivedList;
905       DerivedList _derived_types;
906
907       static bool isInstance(naGhostType* ghost_type, bool& is_weak)
908       {
909         if( !ghost_type || !getSingletonPtr() )
910           return false;
911
912         return getSingletonPtr()->GhostMetadata::isInstance( ghost_type,
913                                                              is_weak );
914       }
915
916       template<class RefPtr, bool is_weak>
917       static
918       typename boost::enable_if_c<
919         !is_weak,
920         RefPtr
921       >::type
922       getPtr(void* ptr)
923       {
924         typedef shared_ptr_storage<strong_ref> storage_type;
925         if( ptr )
926           return storage_type::template get<RefPtr>(
927             static_cast<typename storage_type::storage_type*>(ptr)
928           );
929         else
930           return RefPtr();
931       }
932
933       template<class RefPtr, bool is_weak>
934       static
935       typename boost::enable_if_c<
936         is_weak && supports_weak_ref<T>::value,
937         RefPtr
938       >::type
939       getPtr(void* ptr)
940       {
941         typedef shared_ptr_storage<weak_ref> storage_type;
942         if( ptr )
943           return storage_type::template get<RefPtr>(
944             static_cast<typename storage_type::storage_type*>(ptr)
945           );
946         else
947           return RefPtr();
948       }
949
950       template<class RefPtr, bool is_weak>
951       static
952       typename boost::enable_if_c<
953         is_weak && !supports_weak_ref<T>::value,
954         RefPtr
955       >::type
956       getPtr(void* ptr)
957       {
958         return RefPtr();
959       }
960
961       void addDerived( const internal::GhostMetadata* derived_meta,
962                        to_nasal_t to_nasal_func,
963                        from_nasal_t from_nasal_func )
964       {
965         GhostMetadata::addDerived(derived_meta);
966         _derived_types.push_back(DerivedInfo(to_nasal_func, from_nasal_func));
967       }
968
969       template<class BaseGhost>
970       static
971       typename boost::enable_if
972         < boost::is_polymorphic<typename BaseGhost::raw_type>,
973           naRef
974         >::type
975       toNasal( naContext c,
976                const typename BaseGhost::strong_ref& base_ref,
977                bool strong )
978       {
979         typename BaseGhost::raw_type* ptr = get_pointer(base_ref);
980
981         // Check first if passed pointer can by converted to instance of class
982         // this ghost wraps.
983         if(   !boost::is_same
984                  < typename BaseGhost::raw_type,
985                    typename Ghost::raw_type
986                  >::value
987             && dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
988           return naNil();
989
990         if( !getSingletonPtr() )
991         {
992           SG_LOG
993           (
994             SG_NASAL,
995             SG_INFO,
996             "Ghost::getTypeFor: can not get type for unregistered ghost"
997           );
998           return naNil();
999         }
1000
1001         strong_ref ref =
1002           static_pointer_cast<typename Ghost::raw_type>(base_ref);
1003
1004         // Now check if we can further downcast to one of our derived classes.
1005         for( typename DerivedList::reverse_iterator
1006                derived = getSingletonPtr()->_derived_types.rbegin();
1007                derived != getSingletonPtr()->_derived_types.rend();
1008              ++derived )
1009         {
1010           naRef ghost = (derived->to_nasal)(c, ref, strong);
1011
1012           if( !naIsNil(ghost) )
1013             return ghost;
1014         }
1015
1016         // If base is not an instance of any derived class, this class has to
1017         // be the dynamic type.
1018         return strong
1019              ? create<false>(c, ref)
1020              : create<true>(c, ref);
1021       }
1022
1023       template<class BaseGhost>
1024       static
1025       typename boost::disable_if
1026         < boost::is_polymorphic<typename BaseGhost::raw_type>,
1027           naRef
1028         >::type
1029         toNasal( naContext c,
1030                  const typename BaseGhost::strong_ref& ref,
1031                  bool strong )
1032       {
1033         // For non polymorphic classes there is no possibility to get the actual
1034         // dynamic type, therefore we can only use its static type.
1035         return strong
1036              ? create<false>(c, ref)
1037              : create<true>(c, ref);
1038       }
1039
1040       template<class Type>
1041       static Type fromNasalWithCast(naContext c, naRef me)
1042       {
1043         return Type(fromNasal(c, me));
1044       }
1045
1046       static Ghost* getSingletonPtr()
1047       {
1048         return getSingletonHolder().get();
1049       }
1050
1051       template<class Ret>
1052       getter_t to_getter(Ret (raw_type::*getter)() const)
1053       {
1054         typedef typename boost::call_traits<Ret>::param_type param_type;
1055         naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
1056
1057         // Getter signature: naRef(raw_type&, naContext)
1058         return boost::bind
1059         (
1060           to_nasal_,
1061           _2,
1062           boost::bind(getter, _1)
1063         );
1064       }
1065
1066       template<class Param>
1067       setter_t to_setter(void (raw_type::*setter)(Param))
1068       {
1069         // Setter signature: void(raw_type&, naContext, naRef)
1070         return boost::bind
1071         (
1072           setter,
1073           _1,
1074           boost::bind(from_nasal_ptr<Param>::get(), _2, _3)
1075         );
1076       }
1077
1078       /**
1079        * Invoke a method which writes the converted parameter to a reference
1080        */
1081       template<class Param>
1082       static
1083       bool convert_param_invoker
1084       (
1085         const boost::function<bool ( raw_type&,
1086                                      const std::string&,
1087                                      Param& )>& func,
1088         raw_type& obj,
1089         naContext c,
1090         const std::string& key,
1091         naRef& out
1092       )
1093       {
1094         Param p;
1095         if( !func(obj, key, p) )
1096           return false;
1097
1098         out = to_nasal(c, p);
1099         return true;
1100       };
1101
1102       /**
1103        * Invoke a method which returns a value and convert it to Nasal.
1104        */
1105       template<class Ret>
1106       static
1107       typename boost::disable_if<boost::is_void<Ret>, naRef>::type
1108       method_invoker
1109       (
1110         const boost::function<Ret (raw_type&, const CallContext&)>& func,
1111         raw_type& obj,
1112         const CallContext& ctx
1113       )
1114       {
1115         return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
1116       };
1117
1118       /**
1119        * Invoke a method which returns void and "convert" it to nil.
1120        */
1121       template<class Ret>
1122       static
1123       typename boost::enable_if<boost::is_void<Ret>, naRef>::type
1124       method_invoker
1125       (
1126         const boost::function<Ret (raw_type&, const CallContext&)>& func,
1127         raw_type& obj,
1128         const CallContext& ctx
1129       )
1130       {
1131         func(obj, ctx);
1132         return naNil();
1133       };
1134
1135       /**
1136        * Extract argument by index from nasal::CallContext and convert to given
1137        * type.
1138        */
1139       template<class Arg>
1140       static
1141       typename boost::disable_if<
1142         internal::reduced_is_same<Arg, CallContext>,
1143         typename from_nasal_ptr<Arg>::return_type
1144       >::type
1145       arg_from_nasal(const CallContext& ctx, size_t index)
1146       {
1147         return ctx.requireArg<Arg>(index);
1148       };
1149
1150       /**
1151        * Specialization to pass through nasal::CallContext.
1152        */
1153       template<class Arg>
1154       static
1155       typename boost::enable_if<
1156         internal::reduced_is_same<Arg, CallContext>,
1157         typename from_nasal_ptr<Arg>::return_type
1158       >::type
1159       arg_from_nasal(const CallContext& ctx, size_t)
1160       {
1161         // Either const CallContext& or CallContext, non-const reference
1162         // does not make sense.
1163         BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
1164         return ctx;
1165       };
1166
1167       typedef std::auto_ptr<Ghost> GhostPtr;
1168       MemberMap         _members;
1169       fallback_getter_t _fallback_getter;
1170       fallback_setter_t _fallback_setter;
1171
1172       explicit Ghost(const std::string& name):
1173         GhostMetadata( name,
1174                        &_ghost_type_strong,
1175                        supports_weak_ref<T>::value ? &_ghost_type_weak : NULL )
1176       {
1177         _ghost_type_strong.destroy =
1178           SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<strong_ref>);
1179         _ghost_type_strong.name = _name_strong.c_str();
1180         _ghost_type_strong.get_member = &Ghost::getMemberStrong;
1181         _ghost_type_strong.set_member = &Ghost::setMemberStrong;
1182
1183         _ghost_type_weak.destroy =
1184           SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<weak_ref>);
1185         _ghost_type_weak.name = _name_weak.c_str();
1186
1187         if( supports_weak_ref<T>::value )
1188         {
1189           _ghost_type_weak.get_member = &Ghost::getMemberWeak;
1190           _ghost_type_weak.set_member = &Ghost::setMemberWeak;
1191         }
1192         else
1193         {
1194           _ghost_type_weak.get_member = 0;
1195           _ghost_type_weak.set_member = 0;
1196         }
1197       }
1198
1199       static GhostPtr& getSingletonHolder()
1200       {
1201         static GhostPtr instance;
1202         return instance;
1203       }
1204
1205       template<bool is_weak>
1206       static
1207       typename boost::enable_if_c<
1208         !is_weak,
1209         naRef
1210       >::type
1211       create(naContext c, const strong_ref& ref_ptr)
1212       {
1213         typedef shared_ptr_storage<strong_ref> storage_type;
1214         return naNewGhost2( c,
1215                             &Ghost::_ghost_type_strong,
1216                             storage_type::ref(ref_ptr) );
1217       }
1218
1219       template<bool is_weak>
1220       static
1221       typename boost::enable_if_c<
1222         is_weak && supports_weak_ref<T>::value,
1223         naRef
1224       >::type
1225       create(naContext c, const strong_ref& ref_ptr)
1226       {
1227         typedef shared_ptr_storage<weak_ref> storage_type;
1228         return naNewGhost2( c,
1229                             &Ghost::_ghost_type_weak,
1230                             storage_type::ref(ref_ptr) );
1231       }
1232
1233       template<bool is_weak>
1234       static
1235       typename boost::enable_if_c<
1236         is_weak && !supports_weak_ref<T>::value,
1237         naRef
1238       >::type
1239       create(naContext, const strong_ref&)
1240       {
1241         return naNil();
1242       }
1243
1244       template<class Type>
1245       static void destroy(void *ptr)
1246       {
1247         typedef shared_ptr_storage<Type> storage_type;
1248         storage_type::unref(
1249           static_cast<typename storage_type::storage_type*>(ptr)
1250         );
1251       }
1252
1253       template<class Type>
1254       static void queueDestroy(void *ptr)
1255       {
1256         _destroy_list.push_back( DestroyList::value_type(&destroy<Type>, ptr) );
1257       }
1258
1259       static void raiseErrorExpired(naContext c, const char* str)
1260       {
1261         Ghost* ghost_info = getSingletonPtr();
1262         naRuntimeError(
1263           c,
1264           "Ghost::%s: ghost has expired '%s'",
1265           str,
1266           ghost_info ? ghost_info->_name_strong.c_str() : "unknown"
1267         );
1268       }
1269
1270       /**
1271        * Callback for retrieving a ghost member.
1272        */
1273       static const char* getMemberImpl( naContext c,
1274                                         raw_type& obj,
1275                                         naRef key,
1276                                         naRef* out )
1277       {
1278         const std::string key_str = nasal::from_nasal<std::string>(c, key);
1279         // TODO merge instance parents with static class parents
1280 //        if( key_str == "parents" )
1281 //        {
1282 //          if( getSingletonPtr()->_parents.empty() )
1283 //            return 0;
1284 //
1285 //          *out = getSingletonPtr()->getParents(c);
1286 //          return "";
1287 //        }
1288
1289         typename MemberMap::iterator member =
1290           getSingletonPtr()->_members.find(key_str);
1291
1292         if( member == getSingletonPtr()->_members.end() )
1293         {
1294           fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
1295           if(    !fallback_get
1296               || !fallback_get(obj, c, key_str, *out) )
1297             return 0;
1298         }
1299         else if( member->second.func )
1300           *out = member->second.func->get_naRef(c);
1301         else if( !member->second.getter.empty() )
1302           *out = member->second.getter(obj, c);
1303         else
1304           return "Read-protected member";
1305
1306         return "";
1307       }
1308
1309       static const char*
1310       getMemberWeak(naContext c, void* ghost, naRef key, naRef* out)
1311       {
1312         // Keep a strong reference while retrieving member, to prevent deleting
1313         // object in between.
1314         strong_ref ref = getPtr<strong_ref, true>(ghost);
1315         if( !ref )
1316           raiseErrorExpired(c, "getMember");
1317
1318         return getMemberImpl(c, *get_pointer(ref), key, out);
1319       }
1320
1321       static const char*
1322       getMemberStrong(naContext c, void* ghost, naRef key, naRef* out)
1323       {
1324         // Just get a raw pointer as we are keeping a strong reference as ghost
1325         // anyhow.
1326         raw_type* ptr = getPtr<raw_type*, false>(ghost);
1327         return getMemberImpl(c, *ptr, key, out);
1328       }
1329
1330       /**
1331        * Callback for writing to a ghost member.
1332        */
1333       static void setMemberImpl( naContext c,
1334                                  raw_type& obj,
1335                                  naRef field,
1336                                  naRef val )
1337       {
1338         const std::string key = nasal::from_nasal<std::string>(c, field);
1339         const MemberMap& members = getSingletonPtr()->_members;
1340
1341         typename MemberMap::const_iterator member = members.find(key);
1342         if( member == members.end() )
1343         {
1344           fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
1345           if( !fallback_set )
1346             naRuntimeError(c, "ghost: No such member: %s", key.c_str());
1347           else if( !fallback_set(obj, c, key, val) )
1348             naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
1349         }
1350         else if( member->second.setter.empty() )
1351           naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
1352         else if( member->second.func )
1353           naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
1354         else
1355           member->second.setter(obj, c, val);
1356       }
1357
1358       static void
1359       setMemberWeak(naContext c, void* ghost, naRef field, naRef val)
1360       {
1361         // Keep a strong reference while retrieving member, to prevent deleting
1362         // object in between.
1363         strong_ref ref = getPtr<strong_ref, true>(ghost);
1364         if( !ref )
1365           raiseErrorExpired(c, "setMember");
1366
1367         setMemberImpl(c, *get_pointer(ref), field, val);
1368       }
1369
1370       static void
1371       setMemberStrong(naContext c, void* ghost, naRef field, naRef val)
1372       {
1373         // Just get a raw pointer as we are keeping a strong reference as ghost
1374         // anyhow.
1375         raw_type* ptr = getPtr<raw_type*, false>(ghost);
1376         setMemberImpl(c, *ptr, field, val);
1377       }
1378   };
1379
1380   template<class T>
1381   naGhostType
1382   Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
1383   ::_ghost_type_strong;
1384
1385   template<class T>
1386   naGhostType
1387   Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
1388   ::_ghost_type_weak;
1389
1390 } // namespace nasal
1391
1392 // Needs to be outside any namespace to make ADL work
1393 /**
1394  * Convert every shared pointer to a ghost.
1395  */
1396 template<class T>
1397 typename boost::enable_if<
1398   nasal::internal::has_element_type<
1399     typename nasal::internal::reduced_type<T>::type
1400   >,
1401   naRef
1402 >::type
1403 to_nasal_helper(naContext c, T ptr)
1404 {
1405   typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
1406   return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
1407 }
1408
1409 /**
1410  * Convert nasal ghosts/hashes to shared pointer (of a ghost).
1411  */
1412 template<class T>
1413 typename boost::enable_if<
1414   nasal::internal::has_element_type<
1415     typename nasal::internal::reduced_type<T>::type
1416   >,
1417   T
1418 >::type
1419 from_nasal_helper(naContext c, naRef ref, const T*)
1420 {
1421   typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
1422   return T(nasal::Ghost<strong_ref>::fromNasal(c, ref));
1423 }
1424
1425 /**
1426  * Convert any pointer to a SGReferenced based object to a ghost.
1427  */
1428 template<class T>
1429 typename boost::enable_if_c<
1430      boost::is_base_of<SGReferenced, T>::value
1431   || boost::is_base_of<SGWeakReferenced, T>::value,
1432   naRef
1433 >::type
1434 to_nasal_helper(naContext c, T* ptr)
1435 {
1436   return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
1437 }
1438
1439 /**
1440  * Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
1441  */
1442 template<class T>
1443 typename boost::enable_if_c<
1444      boost::is_base_of<
1445        SGReferenced,
1446        typename boost::remove_pointer<T>::type
1447      >::value
1448   || boost::is_base_of<
1449        SGWeakReferenced,
1450        typename boost::remove_pointer<T>::type
1451      >::value,
1452   T
1453 >::type
1454 from_nasal_helper(naContext c, naRef ref, const T*)
1455 {
1456   typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
1457   return T(nasal::Ghost<TypeRef>::fromNasal(c, ref));
1458 }
1459
1460 /**
1461  * Convert any pointer to a osg::Referenced based object to a ghost.
1462  */
1463 template<class T>
1464 typename boost::enable_if<
1465   boost::is_base_of<osg::Referenced, T>,
1466   naRef
1467 >::type
1468 to_nasal_helper(naContext c, T* ptr)
1469 {
1470   return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<T>(ptr));
1471 }
1472
1473 /**
1474  * Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
1475  */
1476 template<class T>
1477 typename boost::enable_if<
1478   boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
1479   T
1480 >::type
1481 from_nasal_helper(naContext c, naRef ref, const T*)
1482 {
1483   typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
1484   return T(nasal::Ghost<TypeRef>::fromNasal(c, ref));
1485 }
1486
1487 #endif /* SG_NASAL_GHOST_HXX_ */