]> git.mxchange.org Git - simgear.git/commitdiff
cppbind.Ghost: register _set called on setting new properties.
authorThomas Geymayer <tomgey@gmail.com>
Mon, 5 May 2014 12:49:50 +0000 (14:49 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Mon, 5 May 2014 13:06:09 +0000 (15:06 +0200)
simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/cppbind_test.cxx

index 834965886d492bf49a53fb103283708e3129736c..2902560572c375666c917febb228c98b7990b329 100644 (file)
@@ -214,6 +214,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_setter_t;
 
       class MethodHolder:
         public internal::MethodHolder
@@ -390,6 +394,9 @@ namespace nasal
             );
         }
 
+        if( !_fallback_setter )
+          _fallback_setter = base->_fallback_setter;
+
         return *this;
       }
 
@@ -498,6 +505,47 @@ namespace nasal
         return *this;
       }
 
+      /**
+       * Register a function which is called upon setting an unknown member of
+       * this ghost.
+       */
+      Ghost& _set(const fallback_setter_t& setter)
+      {
+        _fallback_setter = setter;
+        return *this;
+      }
+
+      /**
+       * Register a method which is called upon setting an unknown member of
+       * this ghost.
+       *
+       * @code{cpp}
+       * class MyClass
+       * {
+       *   public:
+       *     bool setMember( const std::string& key,
+       *                     const std::string& value );
+       * }
+       *
+       * Ghost<MyClassPtr>::init("Test")
+       *   ._set(&MyClass::setMember);
+       * @endcode
+       */
+      template<class Param>
+      Ghost _set(bool (raw_type::*setter)(const std::string&, Param))
+      {
+        // Setter signature: bool( naContext,
+        //                         raw_type&,
+        //                         const std::string&,
+        //                         naRef )
+        return _set(boost::bind(
+          setter,
+          _2,
+          _3,
+          boost::bind(from_nasal_ptr<Param>::get(), _1, _4)
+        ));
+      }
+
       /**
        * Register anything that accepts an object instance and a
        * nasal::CallContext and returns naRef as method.
@@ -835,7 +883,8 @@ namespace nasal
       };
 
       typedef std::auto_ptr<Ghost> GhostPtr;
-      MemberMap _members;
+      MemberMap         _members;
+      fallback_setter_t _fallback_setter;
 
       explicit Ghost(const std::string& name):
         GhostMetadata(name, &_ghost_type)
@@ -913,17 +962,23 @@ namespace nasal
       static void setMember(naContext c, void* g, naRef field, naRef val)
       {
         const std::string key = nasal::from_nasal<std::string>(c, field);
-        typename MemberMap::iterator member =
-          getSingletonPtr()->_members.find(key);
+        const MemberMap& members = getSingletonPtr()->_members;
 
-        if( member == getSingletonPtr()->_members.end() )
-          naRuntimeError(c, "ghost: No such member: %s", key.c_str());
+        typename MemberMap::const_iterator member = members.find(key);
+        if( member == members.end() )
+        {
+          fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
+          if( !fallback_set )
+            naRuntimeError(c, "ghost: No such member: %s", key.c_str());
+          else if( !fallback_set(c, *getRawPtr(g), key, val) )
+            naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
+        }
         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);
+        else
+          member->second.setter(c, *getRawPtr(g), val);
       }
   };
 
index 2a8abe4275d4aea7c5a651212125cf4732aeae67..4910fa4ab590b8fa995c838425505b186049842a 100644 (file)
@@ -40,6 +40,10 @@ struct Base
   void setVar(const std::string v) { var = v; }
 
   unsigned long getThis() const { return (unsigned long)this; }
+  bool genericSet(const std::string& key, const std::string& val)
+  {
+    return key == "test";
+  }
 };
 
 void baseVoidFunc(Base& b) {}
@@ -206,7 +210,8 @@ int main(int argc, char* argv[])
     .method("int2args", &baseFunc2Args)
     .method("bool2args", &Base::test2Args)
     .method("str_ptr", &testPtr)
-    .method("this", &Base::getThis);
+    .method("this", &Base::getThis)
+    ._set(&Base::genericSet);
   Ghost<DerivedPtr>::init("DerivedPtr")
     .bases<BasePtr>()
     .member("x", &Derived::getX, &Derived::setX)
@@ -319,6 +324,18 @@ 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 )
+
   //----------------------------------------------------------------------------
   // Test nasal::CallContext
   //----------------------------------------------------------------------------