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