From b101f64cd830d730039b3f9f45fbd98c19dc7252 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Mon, 5 May 2014 14:49:50 +0200 Subject: [PATCH] cppbind.Ghost: register _set called on setting new properties. --- simgear/nasal/cppbind/Ghost.hxx | 69 +++++++++++++++++++++++--- simgear/nasal/cppbind/cppbind_test.cxx | 19 ++++++- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 83496588..29025605 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -214,6 +214,10 @@ namespace nasal typedef boost::function getter_t; typedef boost::function setter_t; typedef boost::function method_t; + typedef boost::function 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::init("Test") + * ._set(&MyClass::setMember); + * @endcode + */ + template + 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::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 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(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); } }; diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index 2a8abe42..4910fa4a 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -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::init("DerivedPtr") .bases() .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(c, ret) == 3 ) + //---------------------------------------------------------------------------- // Test nasal::CallContext //---------------------------------------------------------------------------- -- 2.39.5