From: Thomas Geymayer Date: Sun, 18 May 2014 11:31:31 +0000 (+0200) Subject: cppbind.Ghost: register _get called on retrieving unset member. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=289777bd99877d8d1ab439744bff5865e426cab4;p=simgear.git cppbind.Ghost: register _get called on retrieving unset member. Allow registering a callback on ghosts called upon retrieving an unset member. --- diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 263c9d85..e27eb066 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -220,6 +220,10 @@ namespace nasal typedef boost::function getter_t; typedef boost::function setter_t; typedef boost::function method_t; + typedef boost::function fallback_getter_t; typedef boost::function_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::init("Test") + * ._get(&MyClass::getMember); + * @endcode + */ + template + Ghost& _get(bool (raw_type::*getter)(const std::string&, Param&)) + { + return _get(boost::bind( + convert_param_invoker, 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::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 + static + bool convert_param_invoker + ( + const boost::function& 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 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)); diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index 289a13e1..098b21af 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -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::init("DerivedPtr") .bases() .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(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(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(c, ret) == "generic-get" ); + } //---------------------------------------------------------------------------- // Test nasal::CallContext