]> git.mxchange.org Git - simgear.git/commitdiff
cppbind.Ghost: register _get called on retrieving unset member.
authorThomas Geymayer <tomgey@gmail.com>
Sun, 18 May 2014 11:31:31 +0000 (13:31 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 18 May 2014 11:34:06 +0000 (13:34 +0200)
Allow registering a callback on ghosts called upon retrieving
an unset member.

simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/cppbind_test.cxx

index 263c9d857e4b114955f33c8aa2a907feb4cfba94..e27eb06686c8849f65333e8a1beb9ac189997ce2 100644 (file)
@@ -220,6 +220,10 @@ 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::function<bool( naContext,
+                                    raw_type&,
+                                    const std::string&,
+                                    naRef& )>  fallback_getter_t;
       typedef boost::function<bool( naContext,
                                     raw_type&,
                                     const std::string&,
@@ -402,6 +406,8 @@ namespace nasal
 
         if( !_fallback_setter )
           _fallback_setter = base->_fallback_setter;
+        if( !_fallback_getter )
+          _fallback_getter = base->_fallback_getter;
 
         return *this;
       }
@@ -511,6 +517,69 @@ namespace nasal
         return *this;
       }
 
+      /**
+       * Register a function which is called upon retrieving an unknown member
+       * of this ghost.
+       */
+      Ghost& _get(const fallback_getter_t& getter)
+      {
+        _fallback_getter = getter;
+        return *this;
+      }
+
+      /**
+       * Register a method which is called upon retrieving an unknown member of
+       * this ghost.
+       *
+       * @code{cpp}
+       * class MyClass
+       * {
+       *   public:
+       *     bool getMember( const std::string& key,
+       *                     std::string& value_out );
+       * }
+       *
+       * Ghost<MyClassPtr>::init("Test")
+       *   ._get(&MyClass::getMember);
+       * @endcode
+       */
+      template<class Param>
+      Ghost& _get(bool (raw_type::*getter)(const std::string&, Param&))
+      {
+        return _get(boost::bind(
+          convert_param_invoker<Param>, getter, _1, _2, _3, _4
+        ));
+      }
+
+      /**
+       * Register a method which is called upon retrieving an unknown member of
+       * this ghost.
+       *
+       * @code{cpp}
+       * class MyClass
+       * {
+       *   public:
+       *     bool getMember( naContext c,
+       *                     const std::string& key,
+       *                     naRef& value_out );
+       * }
+       *
+       * Ghost<MyClassPtr>::init("Test")
+       *   ._get(&MyClass::getMember);
+       * @endcode
+       */
+      Ghost& _get(bool (raw_type::*getter)( naContext,
+                                            const std::string&,
+                                            naRef& ))
+      {
+        // Getter signature: bool( naContext,
+        //                         raw_type&,
+        //                         const std::string&,
+        //                         naRef& )
+
+        return _get( boost::bind(getter, _2, _1, _3, _4) );
+      }
+
       /**
        * Register a function which is called upon setting an unknown member of
        * this ghost.
@@ -861,6 +930,29 @@ namespace nasal
         );
       }
 
+      /**
+       * Invoke a method which writes the converted parameter to a reference
+       */
+      template<class Param>
+      static
+      bool convert_param_invoker
+      (
+        const boost::function<bool ( raw_type&,
+                                     const std::string&,
+                                     Param& )>& func,
+        naContext c,
+        raw_type& obj,
+        const std::string& key,
+        naRef& out
+      )
+      {
+        Param p;
+        if( !func(obj, key, p) )
+          return false;
+
+        out = to_nasal(c, p);
+        return true;
+      };
 
       /**
        * Invoke a method which returns a value and convert it to Nasal.
@@ -929,6 +1021,7 @@ namespace nasal
 
       typedef std::auto_ptr<Ghost> GhostPtr;
       MemberMap         _members;
+      fallback_getter_t _fallback_getter;
       fallback_setter_t _fallback_setter;
 
       explicit Ghost(const std::string& name):
@@ -989,9 +1082,13 @@ namespace nasal
           getSingletonPtr()->_members.find(key_str);
 
         if( member == getSingletonPtr()->_members.end() )
-          return 0;
-
-        if( member->second.func )
+        {
+          fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
+          if(    !fallback_get
+              || !fallback_get(c, *getRawPtr(g), key_str, *out) )
+            return 0;
+        }
+        else if( member->second.func )
           *out = member->second.func->get_naRef(c);
         else if( !member->second.getter.empty() )
           *out = member->second.getter(c, *getRawPtr(g));
index 289a13e1090dd920f28f2face055371d970e3356..098b21afe988817996b5478445481db6654ac9da 100644 (file)
@@ -44,6 +44,14 @@ struct Base
   {
     return key == "test";
   }
+  bool genericGet(const std::string& key, std::string& val_out)
+  {
+    if( key != "get_test" )
+      return false;
+
+    val_out = "generic-get";
+    return true;
+  }
 };
 
 void baseVoidFunc(Base& b) {}
@@ -218,7 +226,8 @@ int main(int argc, char* argv[])
     .method("bool2args", &Base::test2Args)
     .method("str_ptr", &testPtr)
     .method("this", &Base::getThis)
-    ._set(&Base::genericSet);
+    ._set(&Base::genericSet)
+    ._get(&Base::genericGet);
   Ghost<DerivedPtr>::init("DerivedPtr")
     .bases<BasePtr>()
     .member("x", &Derived::getX, &Derived::setX)
@@ -346,17 +355,32 @@ int main(int argc, char* argv[])
   VERIFY( objects[1] == d2 );
   VERIFY( objects[2] == d3 );
 
-  // Calling fallback setter for unset values
-  const char* src_code = "me.test = 3;";
-  int errLine = -1;
-  naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0,
-                            (char*)src_code, strlen(src_code),
-                            &errLine );
-  ret = naCallMethod(code, derived, 0, 0, naNil());
-
-  VERIFY( !naGetError(c) ) // TODO real error check (this seems to always
-                           //      return 0...
-  VERIFY( from_nasal<int>(c, ret) == 3 )
+  {
+    // Calling fallback setter for unset values
+    const char* src_code = "me.test = 3;";
+    int errLine = -1;
+    naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0,
+                              (char*)src_code, strlen(src_code),
+                              &errLine );
+    ret = naCallMethod(code, derived, 0, 0, naNil());
+
+    VERIFY( !naGetError(c) ) // TODO real error check (this seems to always
+                             //      return 0...
+    VERIFY( from_nasal<int>(c, ret) == 3 )
+  }
+  {
+    // Calling generic (fallback) getter
+    const char* src_code = "var a = me.get_test;";
+    int errLine = -1;
+    naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0,
+                              (char*)src_code, strlen(src_code),
+                              &errLine );
+    ret = naCallMethod(code, derived, 0, 0, naNil());
+
+    VERIFY( !naGetError(c) ) // TODO real error check (this seems to always
+                             //      return 0...
+    VERIFY( from_nasal<std::string>(c, ret) == "generic-get" );
+  }
 
   //----------------------------------------------------------------------------
   // Test nasal::CallContext