]> git.mxchange.org Git - simgear.git/commitdiff
cppbind: rework to allow binding nearly everything.
authorThomas Geymayer <tomgey@gmail.com>
Sun, 3 Mar 2013 18:26:25 +0000 (19:26 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 3 Mar 2013 18:28:39 +0000 (19:28 +0100)
It is now possible to register all types of member function
and free functions as methods for nasal::Ghost objects.
The return value and arguments are converte automatically
to the required types.

Also usage is simplified by removing replacing the old
method and method_func with a single method function
which only needs a name for the method and something
callable.

simgear/nasal/cppbind/CMakeLists.txt
simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/cppbind_test.cxx
simgear/nasal/cppbind/detail/functor_templates.hxx [new file with mode: 0644]
simgear/nasal/cppbind/from_nasal.hxx
simgear/nasal/cppbind/to_nasal.cxx
simgear/nasal/cppbind/to_nasal.hxx

index 18507d8a29ac312faf8e6f58de0361cc06736378..ed8272fd5c044a0041b82dd6928f006d2022694f 100644 (file)
@@ -10,6 +10,10 @@ set(HEADERS
   to_nasal.hxx
 )
 
+set(DETAIL_HEADERS
+  detail/functor_templates.hxx
+)
+
 set(SOURCES
   NasalHash.cxx
   NasalString.cxx
@@ -18,6 +22,7 @@ set(SOURCES
 )
 
 simgear_component(nasal/cppbind nasal/cppbind "${SOURCES}" "${HEADERS}")
+simgear_component(nasal/cppbind/detail nasal/cppbind/detail "" "${DETAIL_HEADERS}")
 
 if(ENABLE_TESTS)
 
index 88133e9d6ed80b76b9a9cdddb82183a614433214..a01e9d74b1cfafa9942eb2f5a0214cd880d7c22e 100644 (file)
@@ -30,6 +30,8 @@
 #include <boost/function.hpp>
 #include <boost/lambda/lambda.hpp>
 #include <boost/mpl/has_xxx.hpp>
+#include <boost/preprocessor/iteration/iterate.hpp>
+#include <boost/shared_ptr.hpp>
 #include <boost/utility/enable_if.hpp>
 
 #include <map>
@@ -108,6 +110,16 @@ namespace nasal
         }
     };
 
+    /**
+     * Hold callable method and convert to Nasal function if required.
+     */
+    class MethodHolder
+    {
+      public:
+        virtual ~MethodHolder() {}
+        virtual naRef get_naRef(naContext c) = 0;
+    };
+
     BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
   }
 
@@ -131,12 +143,13 @@ namespace nasal
      * @param def   Default value returned if too few arguments available
      */
     template<class T>
-    T getArg(size_t index, const T& def = T()) const
+    typename from_nasal_ptr<T>::return_type
+    getArg(size_t index, const T& def = T()) const
     {
       if( index >= argc )
         return def;
 
-      return from_nasal<T>(c, args[index]);
+      return (*from_nasal_ptr<T>::get())(c, args[index]);
     }
 
     /**
@@ -144,12 +157,13 @@ namespace nasal
      * are to few arguments available.
      */
     template<class T>
-    T requireArg(size_t index) const
+    typename from_nasal_ptr<T>::return_type
+    requireArg(size_t index) const
     {
       if( index >= argc )
         naRuntimeError(c, "Missing required arg #%d", index);
 
-      return from_nasal<T>(c, args[index]);
+      return (*from_nasal_ptr<T>::get())(c, args[index]);
     }
 
     naContext   c;
@@ -168,10 +182,13 @@ namespace nasal
    *     void setX(int x);
    *     int getX() const;
    *
-   *     naRef myMember(naContext c, int argc, naRef* args);
+   *     int myMember();
+   *     void doSomethingElse(const nasal::CallContext& ctx);
    * }
    * typedef boost::shared_ptr<MyClass> MyClassPtr;
    *
+   * std::string myOtherFreeMember(int num);
+   *
    * void exposeClasses()
    * {
    *   // Register a nasal ghost type for MyClass. This needs to be done only
@@ -184,9 +201,12 @@ namespace nasal
    *     .member("x_readonly", &MyClass::getX)
    *     // It is also possible to expose writeonly members
    *     .member("x_writeonly", &MyClass::setX)
-   *     // Methods use a slightly different syntax - The pointer to the member
-   *     // function has to be passed as template argument
-   *     .method<&MyClass::myMember>("myMember");
+   *     // Methods can be nearly anything callable and accepting a reference
+   *     // to an instance of the class type. (member functions, free functions
+   *     // and anything else bindable using boost::function and boost::bind)
+   *     .method("myMember", &MyClass::myMember)
+   *     .method("doSomething", &MyClass::doSomethingElse)
+   *     .method("other", &myOtherFreeMember);
    * }
    * @endcode
    */
@@ -204,7 +224,52 @@ namespace nasal
       typedef boost::function<naRef(naContext, raw_type&)>          getter_t;
       typedef boost::function<void(naContext, raw_type&, naRef)>    setter_t;
       typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
-      typedef boost::shared_ptr<method_t>                           method_ptr;
+      typedef boost::shared_ptr<internal::MethodHolder> MethodHolderPtr;
+
+      class MethodHolder:
+        public internal::MethodHolder
+      {
+        public:
+          MethodHolder():
+            _naRef(naNil())
+          {}
+
+          explicit MethodHolder(const method_t& method):
+            _method(method),
+            _naRef(naNil())
+          {}
+
+          virtual naRef get_naRef(naContext c)
+          {
+            if( naIsNil(_naRef) )
+            {
+              _naRef = naNewFunc(c, naNewCCodeU(c, &MethodHolder::call, this));
+              naSave(c, _naRef);
+            }
+            return _naRef;
+          }
+
+        protected:
+          method_t  _method;
+          naRef     _naRef;
+
+          static naRef call( naContext c,
+                             naRef me,
+                             int argc,
+                             naRef* args,
+                             void* user_data )
+          {
+            MethodHolder* holder = static_cast<MethodHolder*>(user_data);
+            if( !holder )
+              naRuntimeError(c, "invalid method holder!");
+
+            return holder->_method
+            (
+              requireObject(c, me),
+              CallContext(c, argc, args)
+            );
+          }
+      };
 
       /**
        * A ghost member. Can consist either of getter and/or setter functions
@@ -212,25 +277,24 @@ namespace nasal
        */
       struct member_t
       {
-        member_t():
-          func(0)
+        member_t()
         {}
 
         member_t( const getter_t& getter,
                   const setter_t& setter,
-                  naCFunction func = 0 ):
+                  const MethodHolderPtr& func = MethodHolderPtr() ):
           getter( getter ),
           setter( setter ),
           func( func )
         {}
 
-        member_t(naCFunction func):
+        explicit member_t(const MethodHolderPtr& func):
           func( func )
         {}
 
-        getter_t    getter;
-        setter_t    setter;
-        naCFunction func;
+        getter_t        getter;
+        setter_t        setter;
+        MethodHolderPtr func;
       };
 
       typedef std::map<std::string, member_t> MemberMap;
@@ -367,22 +431,24 @@ namespace nasal
         member_t m;
         if( getter )
         {
-          typedef typename boost::call_traits<Ret>::param_type param_type;
-          naRef (*to_nasal_)(naContext, param_type) = &nasal::to_nasal;
-
           // Getter signature: naRef(naContext, raw_type&)
-          m.getter = boost::bind(to_nasal_, _1, boost::bind(getter, _2));
+          m.getter = boost::bind
+          (
+            to_nasal_ptr<Ret>::get(),
+            _1,
+            boost::bind(getter, _2)
+          );
         }
 
         if( setter )
         {
-          typename boost::remove_const
-            < typename boost::remove_reference<Param>::type
-            >::type
-          (*from_nasal_)(naContext, naRef) = &nasal::from_nasal;
-
           // Setter signature: void(naContext, raw_type&, naRef)
-          m.setter = boost::bind(setter, _2, boost::bind(from_nasal_, _1, _3));
+          m.setter = boost::bind
+          (
+            setter,
+            _2,
+            boost::bind(from_nasal_ptr<Param>::get(), _1, _3)
+          );
         }
 
         return member(field, m.getter, m.setter);
@@ -439,75 +505,38 @@ namespace nasal
       }
 
       /**
-       * Register a member function.
-       *
-       * @note Because only function pointers can be registered as Nasal
-       *       functions it is needed to pass the function pointer as template
-       *       argument. This allows us to create a separate instance of the
-       *       MemberFunctionWrapper for each registered function and therefore
-       *       provides us with the needed static functions to be passed on to
-       *       Nasal.
-       *
-       * @tparam func   Pointer to member function being registered.
+       * Register anything that accepts an object instance and a
+       * nasal::CallContext and returns naRef as method.
        *
        * @code{cpp}
        * class MyClass
        * {
        *   public:
-       *     naRef myMethod(naContext c, int argc, naRef* args);
+       *     naRef myMethod(const nasal::CallContext& ctx);
        * }
        *
        * Ghost<MyClassPtr>::init("Test")
-       *   .method<&MyClass::myMethod>("myMethod");
+       *   .method("myMethod", &MyClass::myMethod);
        * @endcode
        */
-      template<member_func_t func>
-      Ghost& method(const std::string& name)
+      Ghost& method(const std::string& name, const method_t& func)
       {
-        _members[name].func = &MemberFunctionWrapper<func>::call;
+        _members[name].func.reset( new MethodHolder(func) );
         return *this;
       }
 
       /**
-       * Invoke a method which returns a value and convert it to Nasal.
-       */
-      template<class Ret>
-      static
-      typename boost::disable_if<boost::is_void<Ret>, naRef>::type
-      method_invoker
-      (
-        const boost::function<Ret (raw_type&, const CallContext&)>& func,
-        raw_type& obj,
-        const CallContext& ctx
-      )
-      {
-        typedef typename boost::call_traits<Ret>::param_type param_type;
-        naRef (*to_nasal_)(naContext, param_type) = &nasal::to_nasal;
-
-        return to_nasal_(ctx.c, func(obj, ctx));
-      };
-
-      /**
-       * Invoke a method which returns void and "convert" it to nil.
-       */
-      template<class Ret>
-      static
-      typename boost::enable_if<boost::is_void<Ret>, naRef>::type
-      method_invoker
-      (
-        const boost::function<void (raw_type&, const CallContext&)>& func,
-        raw_type& obj,
-        const CallContext& ctx
-      )
-      {
-        func(obj, ctx);
-        return naNil();
-      };
-
-      /**
-       * Bind any callable entity as method callable from Nasal
+       * Register anything that accepts an object instance and a
+       * nasal::CallContext whith automatic conversion of the return type to
+       * Nasal.
        *
-       * Does not really register method yet!!!
+       * @code{cpp}
+       * class MyClass;
+       * void doIt(const MyClass& c, const nasal::CallContext& ctx);
+       *
+       * Ghost<MyClassPtr>::init("Test")
+       *   .method("doIt", &doIt);
+       * @endcode
        */
       template<class Ret>
       Ghost& method
@@ -516,67 +545,14 @@ namespace nasal
         const boost::function<Ret (raw_type&, const CallContext&)>& func
       )
       {
-//        _members[name].func.reset
-//        (
-          new method_t( boost::bind(method_invoker<Ret>, func, _1, _2) );
-//        );
-        return *this;
-      }
-
-      template<class Ret>
-      struct method_raw
-      {
-        typedef boost::function<Ret (raw_type&, const CallContext&)> type;
-      };
-
-      /**
-       * Bind member function as method callable from Nasal
-       *
-       * Does not really register method yet!!!
-       */
-      template<class Ret>
-      Ghost& method( const std::string& name,
-                     Ret (raw_type::*fn)() const )
-      {
-        return method<Ret>
-        (
-          name,
-          typename method_raw<Ret>::type(boost::bind(fn, _1))
-        );
+        return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
       }
 
-      /**
-       * Register a free function as member function. The object instance is
-       * passed as additional first argument.
-       *
-       * @tparam func   Pointer to free function being registered.
-       *
-       * @note Due to a severe bug in Visual Studio it is not possible to create
-       *       a specialization of #method for free function pointers and
-       *       member function pointers at the same time. Do overcome this
-       *       limitation we had to use a different name for this function.
-       *
-       * @code{cpp}
-       * class MyClass;
-       * naRef myMethod(MyClass& obj, naContext c, int argc, naRef* args);
-       *
-       * Ghost<MyClassPtr>::init("Test")
-       *   .method_func<&myMethod>("myMethod");
-       * @endcode
-       */
-      template<free_func_t func>
-      Ghost& method_func(const std::string& name)
-      {
-        _members[name].func = &FreeFunctionWrapper<func>::call;
-        return *this;
-      }
+#define BOOST_PP_ITERATION_LIMITS (0, 9)
+#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
+#include BOOST_PP_ITERATE()
 
       // TODO use variadic template when supporting C++11
-      /**
-       * Create a Nasal instance of this ghost.
-       *
-       * @param c   Active Nasal context
-       */
       // TODO check if default constructor exists
 //      static naRef create( naContext c )
 //      {
@@ -768,44 +744,65 @@ namespace nasal
       }
 
       /**
-       * Wrapper class to enable registering pointers to member functions as
-       * Nasal function callbacks. We need to use the function pointer as
-       * template parameter to ensure every registered function gets a static
-       * function which can be passed to Nasal.
+       * Invoke a method which returns a value and convert it to Nasal.
+       */
+      template<class Ret>
+      static
+      typename boost::disable_if<boost::is_void<Ret>, naRef>::type
+      method_invoker
+      (
+        const boost::function<Ret (raw_type&, const CallContext&)>& func,
+        raw_type& obj,
+        const CallContext& ctx
+      )
+      {
+        return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
+      };
+
+      /**
+       * Invoke a method which returns void and "convert" it to nil.
        */
-      template<member_func_t func>
-      struct MemberFunctionWrapper
+      template<class Ret>
+      static
+      typename boost::enable_if<boost::is_void<Ret>, naRef>::type
+      method_invoker
+      (
+        const boost::function<Ret (raw_type&, const CallContext&)>& func,
+        raw_type& obj,
+        const CallContext& ctx
+      )
       {
-        /**
-         * Called from Nasal upon invocation of the according registered
-         * function. Forwards the call to the passed object instance.
-         */
-        static naRef call(naContext c, naRef me, int argc, naRef* args)
-        {
-          return (requireObject(c, me).*func)(CallContext(c, argc, args));
-        }
+        func(obj, ctx);
+        return naNil();
       };
 
       /**
-       * Wrapper class to enable registering pointers to free functions (only
-       * external linkage). We need to use the function pointer as template
-       * parameter to ensure every registered function gets a static function
-       * which can be passed to Nasal. Even though we just wrap another simple
-       * function pointer this intermediate step is need to be able to retrieve
-       * the object the function call belongs to and pass it along as argument.
+       * Extract argument by index from nasal::CallContext and convert to given
+       * type.
        */
-      template<free_func_t func>
-      struct FreeFunctionWrapper
+      template<class Arg>
+      static
+      typename boost::disable_if<
+        boost::is_same<Arg, const CallContext&>,
+        typename from_nasal_ptr<Arg>::return_type
+      >::type
+      arg_from_nasal(const CallContext& ctx, size_t index)
       {
-        /**
-         * Called from Nasal upon invocation of the according registered
-         * function. Forwards the call to the passed function pointer and passes
-         * the required parameters.
-         */
-        static naRef call(naContext c, naRef me, int argc, naRef* args)
-        {
-          return func(requireObject(c, me), CallContext(c, argc, args));
-        }
+        return ctx.requireArg<Arg>(index);
+      };
+
+      /**
+       * Specialization to pass through nasal::CallContext.
+       */
+      template<class Arg>
+      static
+      typename boost::enable_if<
+        boost::is_same<Arg, const CallContext&>,
+        typename from_nasal_ptr<Arg>::return_type
+      >::type
+      arg_from_nasal(const CallContext& ctx, size_t)
+      {
+        return ctx;
       };
 
       typedef std::auto_ptr<Ghost> GhostPtr;
@@ -871,7 +868,7 @@ namespace nasal
           return 0;
 
         if( member->second.func )
-          *out = nasal::to_nasal(c, member->second.func);
+          *out = member->second.func->get_naRef(c);
         else if( !member->second.getter.empty() )
           *out = member->second.getter(c, *getRawPtr(g));
         else
@@ -891,8 +888,10 @@ namespace nasal
 
         if( member == getSingletonPtr()->_members.end() )
           naRuntimeError(c, "ghost: No such member: %s", key.c_str());
-        if( member->second.setter.empty() )
+        else if( member->second.setter.empty() )
           naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
+        else if( member->second.func )
+          naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
 
         member->second.setter(c, *getRawPtr(g), val);
       }
index cd80244b7f189f2c25ca271eb19c363d650116c5..90bbf8555a4995b2efed178c199f58fa53ee95e5 100644 (file)
@@ -24,6 +24,8 @@ struct Base
   std::string getString() const { return ""; }
   void setString(const std::string&) {}
   void constVoidFunc() const {}
+  int test1Arg(const std::string& str) const { return str.length(); }
+  bool test2Args(const std::string& s, bool c) { return c && s.empty(); }
 
   std::string var;
   const std::string& getVar() const { return var; }
@@ -32,6 +34,9 @@ struct Base
 
 void baseVoidFunc(Base& b) {}
 void baseConstVoidFunc(const Base& b) {}
+int baseFunc2Args(Base& b, int x, const std::string& s) { return x + s.size(); }
+std::string testPtr(Base& b) { return b.getString(); }
+void baseFuncCallContext(const Base&, const nasal::CallContext&) {}
 
 struct Derived:
   public Base
@@ -61,7 +66,7 @@ naRef to_nasal(naContext c, const BasePtr& base)
   return nasal::Ghost<BasePtr>::create(c, base);
 }
 
-naRef member(Derived&, const nasal::CallContext&) { return naNil(); }
+naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); }
 naRef f_derivedGetX(naContext c, const Derived& d)
 {
   return nasal::to_nasal(c, d.getX());
@@ -126,41 +131,31 @@ int main(int argc, char* argv[])
   Hash mod = hash.createHash("mod");
   mod.set("parent", hash);
 
-  String string( to_nasal(c, "Test") );
-  VERIFY( from_nasal<std::string>(c, string.get_naRef()) == "Test" );
-  VERIFY( string.c_str() == std::string("Test") );
-  VERIFY( string.starts_with(string) );
-  VERIFY( string.starts_with(String(c, "T")) );
-  VERIFY( string.starts_with(String(c, "Te")) );
-  VERIFY( string.starts_with(String(c, "Tes")) );
-  VERIFY( string.starts_with(String(c, "Test")) );
-  VERIFY( !string.starts_with(String(c, "Test1")) );
-  VERIFY( !string.starts_with(String(c, "bb")) );
-  VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) );
-  VERIFY( string.find('e') == 1 );
-  VERIFY( string.find('9') == String::npos );
-  VERIFY( string.find_first_of(String(c, "st")) == 2 );
-  VERIFY( string.find_first_of(String(c, "st"), 3) == 3 );
-  VERIFY( string.find_first_of(String(c, "xyz")) == String::npos );
-  VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 );
-  VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 );
-  VERIFY( string.find_first_not_of(String(c, "abc")) == 0 );
-  VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos );
+  //----------------------------------------------------------------------------
+  // Test exposing classes to Nasal
+  //----------------------------------------------------------------------------
 
   Ghost<BasePtr>::init("BasePtr")
-    .method<&Base::member>("member")
+    .method("member", &Base::member)
+    .method("strlen", &Base::test1Arg)
     .member("str", &Base::getString, &Base::setString)
     .method("str_m", &Base::getString)
     .method("void", &Base::constVoidFunc)
     .member("var_r", &Base::getVar)
     .member("var_w", &Base::setVar)
     .member("var", &Base::getVar, &Base::setVar)
-    /*.method("void", &baseVoidFunc)*/;
+    .method("void", &baseVoidFunc)
+    .method("void_c", &baseConstVoidFunc)
+    .method("int2args", &baseFunc2Args)
+    .method("bool2args", &Base::test2Args)
+    .method("str_ptr", &testPtr);
   Ghost<DerivedPtr>::init("DerivedPtr")
     .bases<BasePtr>()
     .member("x", &Derived::getX, &Derived::setX)
     .member("x_alternate", &f_derivedGetX)
-    .method_func<&member>("free_member");
+    .method("free_fn", &derivedFreeMember)
+    .method("free_member", &derivedFreeMember)
+    .method("baseDoIt", &baseFuncCallContext);
   Ghost<DoubleDerivedPtr>::init("DoubleDerivedPtr")
     .bases<DerivedPtr>();
   Ghost<DoubleDerived2Ptr>::init("DoubleDerived2Ptr")
@@ -222,6 +217,12 @@ int main(int argc, char* argv[])
   derived_obj.set("parents", parents2);
   VERIFY( Ghost<BasePtr>::fromNasal(c, derived_obj.get_naRef()) == d3 );
 
+  // TODO actually do something with the ghosts...
+
+  //----------------------------------------------------------------------------
+  // Test nasal::CallContext
+  //----------------------------------------------------------------------------
+
   naRef args[] = {
     to_nasal(c, std::string("test-arg"))
   };
@@ -233,7 +234,30 @@ int main(int argc, char* argv[])
   naRef args_vec = nasal::to_nasal(c, args);
   VERIFY( naIsVector(args_vec) );
 
-  // TODO actually do something with the ghosts...
+  //----------------------------------------------------------------------------
+  // Test nasal::String
+  //----------------------------------------------------------------------------
+
+  String string( to_nasal(c, "Test") );
+  VERIFY( from_nasal<std::string>(c, string.get_naRef()) == "Test" );
+  VERIFY( string.c_str() == std::string("Test") );
+  VERIFY( string.starts_with(string) );
+  VERIFY( string.starts_with(String(c, "T")) );
+  VERIFY( string.starts_with(String(c, "Te")) );
+  VERIFY( string.starts_with(String(c, "Tes")) );
+  VERIFY( string.starts_with(String(c, "Test")) );
+  VERIFY( !string.starts_with(String(c, "Test1")) );
+  VERIFY( !string.starts_with(String(c, "bb")) );
+  VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) );
+  VERIFY( string.find('e') == 1 );
+  VERIFY( string.find('9') == String::npos );
+  VERIFY( string.find_first_of(String(c, "st")) == 2 );
+  VERIFY( string.find_first_of(String(c, "st"), 3) == 3 );
+  VERIFY( string.find_first_of(String(c, "xyz")) == String::npos );
+  VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 );
+  VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 );
+  VERIFY( string.find_first_not_of(String(c, "abc")) == 0 );
+  VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos );
 
   naFreeContext(c);
 
diff --git a/simgear/nasal/cppbind/detail/functor_templates.hxx b/simgear/nasal/cppbind/detail/functor_templates.hxx
new file mode 100644 (file)
index 0000000..51bb6c9
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef SG_NASAL_GHOST_HXX_
+# error Nasal cppbind - do not include this file!
+#endif
+
+#define n BOOST_PP_ITERATION()
+
+#define SG_GHOST_FUNC_TYPE\
+  boost::function<Ret (raw_type& BOOST_PP_COMMA_IF(n)BOOST_PP_ENUM_PARAMS(n,A))>
+
+  /**
+   * Bind any callable entity accepting an instance of raw_type and an arbitrary
+   * number of arguments as method.
+   */
+  template<
+    class Ret
+    BOOST_PP_COMMA_IF(n)
+    BOOST_PP_ENUM_PARAMS(n, class A)
+  >
+  Ghost& method(const std::string& name, const SG_GHOST_FUNC_TYPE& func)
+  {
+#define SG_GHOST_REQUIRE_ARG(z, n, dummy)\
+    boost::bind(&Ghost::arg_from_nasal<A##n>, _2, n)
+
+    return method<Ret>
+    (
+      name,
+      typename boost::function<Ret (raw_type&, const CallContext&)>
+      ( boost::bind(
+        func,
+        _1
+        BOOST_PP_COMMA_IF(n)
+        BOOST_PP_ENUM(n, SG_GHOST_REQUIRE_ARG,)
+      ))
+    );
+
+#undef SG_GHOST_REQUIRE_ARG
+  }
+
+#define SG_GHOST_MEM_FN(cv)\
+  /**\
+   * Bind a member function with an arbitrary number of arguments as method.\
+   */\
+  template<\
+    class Ret\
+    BOOST_PP_COMMA_IF(n)\
+    BOOST_PP_ENUM_PARAMS(n, class A)\
+  >\
+  Ghost& method\
+  (\
+    const std::string& name,\
+    Ret (raw_type::*fn)(BOOST_PP_ENUM_PARAMS(n,A)) cv\
+  )\
+  {\
+    return method<\
+      Ret\
+      BOOST_PP_COMMA_IF(n)\
+      BOOST_PP_ENUM_PARAMS(n,A)\
+    >(name, SG_GHOST_FUNC_TYPE(fn));\
+  }
+
+
+  SG_GHOST_MEM_FN()
+  SG_GHOST_MEM_FN(const)
+
+#undef SG_GHOST_MEM_FN
+
+  /**
+   * Bind free function accepting an instance of raw_type and an arbitrary
+   * number of arguments as method.
+   */
+  template<
+    class Ret,
+    class Type
+    BOOST_PP_COMMA_IF(n)
+    BOOST_PP_ENUM_PARAMS(n, class A)
+  >
+  Ghost& method
+  (
+    const std::string& name,
+    Ret (*fn)(Type BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,A))
+  )
+  {
+    BOOST_STATIC_ASSERT
+    (( boost::is_convertible<raw_type&, Type>::value
+    //|| boost::is_convertible<raw_type*, Type>::value
+    // TODO check how to do it with pointer...
+    ));
+    return method<Ret>(name, SG_GHOST_FUNC_TYPE(fn));
+  }
+
+#undef n
+#undef SG_GHOST_TYPEDEF_FUNC_TYPE
index 37b636594278dfb11e708dc212a91ceb94a90b44..de1521355b43f6adcefefb0f80a9e3ab85b517c9 100644 (file)
@@ -45,6 +45,24 @@ namespace nasal
     return from_nasal_helper(c, ref, static_cast<T*>(0));
   }
 
+  /**
+   * Get pointer to specific version of from_nasal, converting to a type
+   * compatible to Var.
+   */
+  template<class Var>
+  struct from_nasal_ptr
+  {
+    typedef typename boost::remove_const
+      < typename boost::remove_reference<Var>::type
+      >::type return_type;
+    typedef return_type(*type)(naContext, naRef);
+
+    static type get()
+    {
+      return &from_nasal<return_type>;
+    }
+  };
+
 } // namespace nasal
 
 #endif /* SG_FROM_NASAL_HXX_ */
index 40b3cd4f778fb803c84d0995d6d8f4dd05cf02fe..b5224ad2e1f5d6e034819694b78333c288fde4f5 100644 (file)
@@ -50,7 +50,7 @@ namespace nasal
   }
 
   //----------------------------------------------------------------------------
-  naRef to_nasal(naContext c, naRef ref)
+  naRef to_nasal(naContext c, const naRef& ref)
   {
     return ref;
   }
index c6a80863ca5eb65e0446568534ccded7a70a4f92..eeaf5a97475a5849b69f95f04dbd826ab3690dc3 100644 (file)
@@ -62,7 +62,7 @@ namespace nasal
   /**
    * Simple pass-through of naRef types to allow generic usage of to_nasal
    */
-  naRef to_nasal(naContext c, naRef ref);
+  naRef to_nasal(naContext c, const naRef& ref);
 
   naRef to_nasal(naContext c, const SGPath& path);
     
@@ -116,6 +116,22 @@ namespace nasal
     return ret;
   }
 
+  /**
+   * Wrapper to get pointer to specific version of to_nasal applicable to given
+   * type.
+   */
+  template<class Var>
+  struct to_nasal_ptr
+  {
+    typedef typename boost::call_traits<Var>::param_type param_type;
+    typedef naRef(*type)(naContext, param_type);
+
+    static type get()
+    {
+      return static_cast<type>(&to_nasal);
+    }
+  };
+
   //----------------------------------------------------------------------------
   template<class Vec2>
   typename boost::enable_if<is_vec2<Vec2>, naRef>::type