cppbind.Ghost: register _set called on setting new properties.
This commit is contained in:
@@ -214,6 +214,10 @@ namespace nasal
|
|||||||
typedef boost::function<naRef(naContext, raw_type&)> getter_t;
|
typedef boost::function<naRef(naContext, raw_type&)> getter_t;
|
||||||
typedef boost::function<void(naContext, raw_type&, naRef)> setter_t;
|
typedef boost::function<void(naContext, raw_type&, naRef)> setter_t;
|
||||||
typedef boost::function<naRef(raw_type&, const CallContext&)> method_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:
|
class MethodHolder:
|
||||||
public internal::MethodHolder
|
public internal::MethodHolder
|
||||||
@@ -390,6 +394,9 @@ namespace nasal
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !_fallback_setter )
|
||||||
|
_fallback_setter = base->_fallback_setter;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,6 +505,47 @@ namespace nasal
|
|||||||
return *this;
|
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
|
* Register anything that accepts an object instance and a
|
||||||
* nasal::CallContext and returns naRef as method.
|
* nasal::CallContext and returns naRef as method.
|
||||||
@@ -835,7 +883,8 @@ namespace nasal
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef std::auto_ptr<Ghost> GhostPtr;
|
typedef std::auto_ptr<Ghost> GhostPtr;
|
||||||
MemberMap _members;
|
MemberMap _members;
|
||||||
|
fallback_setter_t _fallback_setter;
|
||||||
|
|
||||||
explicit Ghost(const std::string& name):
|
explicit Ghost(const std::string& name):
|
||||||
GhostMetadata(name, &_ghost_type)
|
GhostMetadata(name, &_ghost_type)
|
||||||
@@ -913,17 +962,23 @@ namespace nasal
|
|||||||
static void setMember(naContext c, void* g, naRef field, naRef val)
|
static void setMember(naContext c, void* g, naRef field, naRef val)
|
||||||
{
|
{
|
||||||
const std::string key = nasal::from_nasal<std::string>(c, field);
|
const std::string key = nasal::from_nasal<std::string>(c, field);
|
||||||
typename MemberMap::iterator member =
|
const MemberMap& members = getSingletonPtr()->_members;
|
||||||
getSingletonPtr()->_members.find(key);
|
|
||||||
|
|
||||||
if( member == getSingletonPtr()->_members.end() )
|
typename MemberMap::const_iterator member = members.find(key);
|
||||||
naRuntimeError(c, "ghost: No such member: %s", key.c_str());
|
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() )
|
else if( member->second.setter.empty() )
|
||||||
naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
|
naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
|
||||||
else if( member->second.func )
|
else if( member->second.func )
|
||||||
naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
|
naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
|
||||||
|
else
|
||||||
member->second.setter(c, *getRawPtr(g), val);
|
member->second.setter(c, *getRawPtr(g), val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ struct Base
|
|||||||
void setVar(const std::string v) { var = v; }
|
void setVar(const std::string v) { var = v; }
|
||||||
|
|
||||||
unsigned long getThis() const { return (unsigned long)this; }
|
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) {}
|
void baseVoidFunc(Base& b) {}
|
||||||
@@ -206,7 +210,8 @@ int main(int argc, char* argv[])
|
|||||||
.method("int2args", &baseFunc2Args)
|
.method("int2args", &baseFunc2Args)
|
||||||
.method("bool2args", &Base::test2Args)
|
.method("bool2args", &Base::test2Args)
|
||||||
.method("str_ptr", &testPtr)
|
.method("str_ptr", &testPtr)
|
||||||
.method("this", &Base::getThis);
|
.method("this", &Base::getThis)
|
||||||
|
._set(&Base::genericSet);
|
||||||
Ghost<DerivedPtr>::init("DerivedPtr")
|
Ghost<DerivedPtr>::init("DerivedPtr")
|
||||||
.bases<BasePtr>()
|
.bases<BasePtr>()
|
||||||
.member("x", &Derived::getX, &Derived::setX)
|
.member("x", &Derived::getX, &Derived::setX)
|
||||||
@@ -319,6 +324,18 @@ int main(int argc, char* argv[])
|
|||||||
VERIFY( objects[1] == d2 );
|
VERIFY( objects[1] == d2 );
|
||||||
VERIFY( objects[2] == d3 );
|
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
|
// Test nasal::CallContext
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user