simgear_component(nasal/cppbind/detail nasal/cppbind/detail "" "${DETAIL_HEADERS}")
add_boost_test(cppbind_ghost
- SOURCES cppbind_test_ghost.cxx
+ SOURCES test/cppbind_test_ghost.cxx
LIBRARIES ${TEST_LIBS}
)
add_boost_test(cppbind_misc
- SOURCES cppbind_test.cxx
+ SOURCES test/cppbind_test.cxx
+ LIBRARIES ${TEST_LIBS}
+)
+
+add_boost_test(nasal_gc_test
+ SOURCES test/nasal_gc_test.cxx
LIBRARIES ${TEST_LIBS}
)
add_boost_test(nasal_num
- SOURCES nasal_num_test.cxx
+ SOURCES test/nasal_num_test.cxx
LIBRARIES ${TEST_LIBS}
)
\ No newline at end of file
+++ /dev/null
-#define BOOST_TEST_MODULE cppbind
-#include <BoostTestTargetConfig.h>
-
-#include "Ghost.hxx"
-#include "NasalHash.hxx"
-#include "NasalString.hxx"
-
-#include <simgear/math/SGMath.hxx>
-#include <simgear/structure/map.hxx>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-#include <cstring>
-
-enum MyEnum
-{
- ENUM_FIRST,
- ENUM_ANOTHER,
- ENUM_LAST
-};
-struct Base
-{
- naRef member(const nasal::CallContext&) { return naNil(); }
- virtual ~Base(){};
-
- std::string getString() const { return ""; }
- void setString(const std::string&) {}
- void constVoidFunc() const {}
- size_t test1Arg(const std::string& str) const { return str.length(); }
- bool test2Args(const std::string& s, bool c) { return c && s.empty(); }
-
- std::string var;
- const std::string& getVar() const { return var; }
- 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";
- }
- bool genericGet(const std::string& key, std::string& val_out) const
- {
- if( key != "get_test" )
- return false;
-
- val_out = "generic-get";
- return true;
- }
-};
-
-void baseVoidFunc(Base& b) {}
-void baseConstVoidFunc(const Base& b) {}
-size_t baseFunc2Args(Base& b, int x, const std::string& s) { return x + s.size(); }
-std::string testPtr(Base& b) { return b.getString(); }
-void baseFuncCallContext(const Base&, const nasal::CallContext&) {}
-
-struct Derived:
- public Base
-{
- int _x;
- int getX() const { return _x; }
- void setX(int x) { _x = x; }
-};
-
-naRef f_derivedGetRandom(const Derived&, naContext)
-{
- return naNil();
-}
-void f_derivedSetX(Derived& d, naContext, naRef r)
-{
- d._x = static_cast<int>(naNumValue(r).num);
-}
-
-struct DoubleDerived:
- public Derived
-{
-
-};
-
-typedef boost::shared_ptr<Base> BasePtr;
-typedef std::vector<BasePtr> BaseVec;
-
-struct DoubleDerived2:
- public Derived
-{
- const BasePtr& getBase() const{return _base;}
- BasePtr _base;
- BaseVec doSomeBaseWork(const BaseVec& v) { return v; }
-};
-
-class SGReferenceBasedClass:
- public SGReferenced
-{
-
-};
-
-class SGWeakReferenceBasedClass:
- public SGWeakReferenced
-{
-
-};
-
-typedef boost::shared_ptr<Derived> DerivedPtr;
-typedef boost::shared_ptr<DoubleDerived> DoubleDerivedPtr;
-typedef boost::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
-typedef SGSharedPtr<SGReferenceBasedClass> SGRefBasedPtr;
-typedef SGSharedPtr<SGWeakReferenceBasedClass> SGWeakRefBasedPtr;
-
-typedef boost::weak_ptr<Derived> DerivedWeakPtr;
-
-naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); }
-naRef f_derivedGetX(const Derived& d, naContext c)
-{
- return nasal::to_nasal(c, d.getX());
-}
-naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
-
-BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
-{
- naContext c = naNewContext();
- naRef r;
-
- using namespace nasal;
-
- r = to_nasal(c, ENUM_ANOTHER);
- BOOST_CHECK_EQUAL(from_nasal<int>(c, r), ENUM_ANOTHER);
-
- r = to_nasal(c, "Test");
- BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
- BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
-
- r = to_nasal(c, std::string("Test"));
- BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
- BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
-
- r = to_nasal(c, 42);
- BOOST_CHECK_EQUAL(naNumValue(r).num, 42);
- BOOST_CHECK_EQUAL(from_nasal<int>(c, r), 42);
-
- r = to_nasal(c, 4.2f);
- BOOST_CHECK_EQUAL(naNumValue(r).num, 4.2f);
- BOOST_CHECK_EQUAL(from_nasal<float>(c, r), 4.2f);
-
- float test_data[3] = {0, 4, 2};
- r = to_nasal(c, test_data);
-
- SGVec2f vec(0,2);
- r = to_nasal(c, vec);
- BOOST_CHECK_EQUAL(from_nasal<SGVec2f>(c, r), vec);
-
- std::vector<int> std_vec;
- r = to_nasal(c, std_vec);
-
- r = to_nasal(c, "string");
- BOOST_CHECK_THROW(from_nasal<int>(c, r), bad_nasal_cast);
-
- Hash hash(c);
- hash.set("vec", r);
- hash.set("vec2", vec);
- hash.set("name", "my-name");
- hash.set("string", std::string("blub"));
- hash.set("func", &f_freeFunction);
-
- BOOST_CHECK_EQUAL(hash.size(), 5);
- for(Hash::const_iterator it = hash.begin(); it != hash.end(); ++it)
- BOOST_CHECK_EQUAL( hash.get<std::string>(it->getKey()),
- it->getValue<std::string>() );
-
- Hash::iterator it1, it2;
- Hash::const_iterator it3 = it1, it4(it2);
- it1 = it2;
- it3 = it2;
-
- r = to_nasal(c, hash);
- BOOST_REQUIRE( naIsHash(r) );
-
- simgear::StringMap string_map = from_nasal<simgear::StringMap>(c, r);
- BOOST_CHECK_EQUAL(string_map.at("vec"), "string");
- BOOST_CHECK_EQUAL(string_map.at("name"), "my-name");
- BOOST_CHECK_EQUAL(string_map.at("string"), "blub");
-
- BOOST_CHECK_EQUAL(hash.get<std::string>("name"), "my-name");
- BOOST_CHECK(naIsString(hash.get("name")));
-
- Hash mod = hash.createHash("mod");
- mod.set("parent", hash);
-
-
- // 'func' is a C++ function registered to Nasal and now converted back to C++
- boost::function<int (int)> f = hash.get<int (int)>("func");
- BOOST_REQUIRE( f );
- BOOST_CHECK_EQUAL(f(3), 3);
-
- boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
- BOOST_REQUIRE( fs );
- BOOST_CHECK_EQUAL(fs(14), "14");
-
- typedef boost::function<void (int)> FuncVoidInt;
- FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
- BOOST_REQUIRE( fvi );
- fvi(123);
-
- typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
- FuncMultiArg fma = hash.get<FuncMultiArg>("func");
- BOOST_REQUIRE( fma );
- BOOST_CHECK_EQUAL(fma("test", 3, .5), "test");
-
- typedef boost::function<naRef (naRef)> naRefMemFunc;
- naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
- BOOST_REQUIRE( fmem );
- naRef ret = fmem(hash.get_naRef()),
- hash_ref = hash.get_naRef();
- BOOST_CHECK( naIsIdentical(ret, hash_ref) );
-
- // Check if nasal::Me gets passed as self/me and remaining arguments are
- // passed on to function
- typedef boost::function<int (Me, int)> MeIntFunc;
- MeIntFunc fmeint = hash.get<MeIntFunc>("func");
- BOOST_CHECK_EQUAL(fmeint(naNil(), 5), 5);
-
- //----------------------------------------------------------------------------
- // Test exposing classes to Nasal
- //----------------------------------------------------------------------------
-
- Ghost<BasePtr>::init("BasePtr")
- .method("member", &Base::member)
- .method("strlen", &Base::test1Arg)
- .member("str", &Base::getString, &Base::setString)
- .method("str_m", &Base::getString)
- .method("void", &Base::constVoidFunc)
- .member("var_r", &Base::getVar)
- .member("var_w", &Base::setVar)
- .member("var", &Base::getVar, &Base::setVar)
- .method("void", &baseVoidFunc)
- .method("void_c", &baseConstVoidFunc)
- .method("int2args", &baseFunc2Args)
- .method("bool2args", &Base::test2Args)
- .method("str_ptr", &testPtr)
- .method("this", &Base::getThis)
- ._set(&Base::genericSet)
- ._get(&Base::genericGet);
- Ghost<DerivedPtr>::init("DerivedPtr")
- .bases<BasePtr>()
- .member("x", &Derived::getX, &Derived::setX)
- .member("x_alternate", &f_derivedGetX)
- .member("x_mixed", &f_derivedGetRandom, &Derived::setX)
- .member("x_mixed2", &Derived::getX, &f_derivedSetX)
- .member("x_w", &f_derivedSetX)
- .method("free_fn", &derivedFreeMember)
- .method("free_member", &derivedFreeMember)
- .method("baseDoIt", &baseFuncCallContext);
- Ghost<DoubleDerivedPtr>::init("DoubleDerivedPtr")
- .bases<DerivedPtr>();
- Ghost<DoubleDerived2Ptr>::init("DoubleDerived2Ptr")
- .bases< Ghost<DerivedPtr> >()
- .member("base", &DoubleDerived2::getBase)
- .method("doIt", &DoubleDerived2::doSomeBaseWork);
-
- Ghost<SGRefBasedPtr>::init("SGRefBasedPtr");
- Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
-
- SGWeakRefBasedPtr weak_ptr(new SGWeakReferenceBasedClass());
- naRef nasal_ref = to_nasal(c, weak_ptr),
- nasal_ptr = to_nasal(c, weak_ptr.get());
-
- BOOST_REQUIRE( naIsGhost(nasal_ref) );
- BOOST_REQUIRE( naIsGhost(nasal_ptr) );
-
- SGWeakRefBasedPtr ptr1 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ref),
- ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
-
- BOOST_CHECK_EQUAL(weak_ptr, ptr1);
- BOOST_CHECK_EQUAL(weak_ptr, ptr2);
-
-
- BOOST_REQUIRE( Ghost<BasePtr>::isInit() );
- nasal::to_nasal(c, DoubleDerived2Ptr());
-
- BasePtr d( new Derived );
- naRef derived = to_nasal(c, d);
- BOOST_REQUIRE( naIsGhost(derived) );
- BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name );
-
- // Get member function from ghost...
- naRef thisGetter = naNil();
- BOOST_CHECK( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
- BOOST_CHECK( naIsFunc(thisGetter) );
-
- // ...and check if it really gets passed the correct instance
- typedef boost::function<unsigned long (Me)> MemFunc;
- MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
- BOOST_REQUIRE( fGetThis );
- BOOST_CHECK_EQUAL( fGetThis(derived), (unsigned long)d.get() );
-
- BasePtr d2( new DoubleDerived );
- derived = to_nasal(c, d2);
- BOOST_CHECK( naIsGhost(derived) );
- BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"),
- naGhost_type(derived)->name );
-
- BasePtr d3( new DoubleDerived2 );
- derived = to_nasal(c, d3);
- BOOST_CHECK( naIsGhost(derived) );
- BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"),
- naGhost_type(derived)->name );
-
- SGRefBasedPtr ref_based( new SGReferenceBasedClass );
- naRef na_ref_based = to_nasal(c, ref_based.get());
- BOOST_CHECK( naIsGhost(na_ref_based) );
- BOOST_CHECK_EQUAL( from_nasal<SGReferenceBasedClass*>(c, na_ref_based),
- ref_based.get() );
- BOOST_CHECK_EQUAL( from_nasal<SGRefBasedPtr>(c, na_ref_based), ref_based );
-
- BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived), d3 );
- BOOST_CHECK_NE( from_nasal<BasePtr>(c, derived), d2 );
- BOOST_CHECK_EQUAL( from_nasal<DerivedPtr>(c, derived),
- boost::dynamic_pointer_cast<Derived>(d3) );
- BOOST_CHECK_EQUAL( from_nasal<DoubleDerived2Ptr>(c, derived),
- boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
- BOOST_CHECK_THROW( from_nasal<DoubleDerivedPtr>(c, derived), bad_nasal_cast );
-
- std::map<std::string, BasePtr> instances;
- BOOST_CHECK( naIsHash(to_nasal(c, instances)) );
-
- std::map<std::string, DerivedPtr> instances_d;
- BOOST_CHECK( naIsHash(to_nasal(c, instances_d)) );
-
- std::map<std::string, int> int_map;
- BOOST_CHECK( naIsHash(to_nasal(c, int_map)) );
-
- std::map<std::string, std::vector<int> > int_vector_map;
- BOOST_CHECK( naIsHash(to_nasal(c, int_vector_map)) );
-
- simgear::StringMap dict =
- simgear::StringMap("hello", "value")
- ("key2", "value2");
- naRef na_dict = to_nasal(c, dict);
- BOOST_REQUIRE( naIsHash(na_dict) );
- BOOST_CHECK_EQUAL( Hash(na_dict, c).get<std::string>("key2"), "value2" );
-
- // Check converting to Ghost if using Nasal hashes with actual ghost inside
- // the hashes parents vector
- std::vector<naRef> parents;
- parents.push_back(hash.get_naRef());
- parents.push_back(derived);
-
- Hash obj(c);
- obj.set("parents", parents);
- BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, obj.get_naRef()), d3 );
-
- // Check recursive parents (aka parent-of-parent)
- std::vector<naRef> parents2;
- parents2.push_back(obj.get_naRef());
- Hash derived_obj(c);
- derived_obj.set("parents", parents2);
- BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived_obj.get_naRef()), d3 );
-
- std::vector<naRef> nasal_objects;
- nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
- nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d2) );
- nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
- naRef obj_vec = to_nasal(c, nasal_objects);
-
- std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
- BOOST_CHECK_EQUAL( objects[0], d );
- BOOST_CHECK_EQUAL( objects[1], d2 );
- BOOST_CHECK_EQUAL( 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());
-
- BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
- // always return 0...
- BOOST_CHECK_EQUAL( 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());
-
- BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
- // always return 0...
- BOOST_CHECK_EQUAL( from_nasal<std::string>(c, ret), "generic-get" );
- }
-
- //----------------------------------------------------------------------------
- // Test nasal::CallContext
- //----------------------------------------------------------------------------
-
-
- int int_vec[] = {1,2,3};
- std::map<std::string, std::string> map;
- naRef args[] = {
- to_nasal(c, std::string("test-arg")),
- to_nasal(c, 4),
- to_nasal(c, int_vec),
- to_nasal(c, map)
- };
- CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args);
- BOOST_CHECK_EQUAL( cc.requireArg<std::string>(0), "test-arg" );
- BOOST_CHECK_EQUAL( cc.getArg<std::string>(0), "test-arg" );
- BOOST_CHECK_EQUAL( cc.getArg<std::string>(10), "" );
- BOOST_CHECK( cc.isString(0) );
- BOOST_CHECK( !cc.isNumeric(0) );
- BOOST_CHECK( !cc.isVector(0) );
- BOOST_CHECK( !cc.isHash(0) );
- BOOST_CHECK( !cc.isGhost(0) );
- BOOST_CHECK( cc.isNumeric(1) );
- BOOST_CHECK( cc.isVector(2) );
- BOOST_CHECK( cc.isHash(3) );
-
- naRef args_vec = nasal::to_nasal(c, args);
- BOOST_CHECK( naIsVector(args_vec) );
-
- //----------------------------------------------------------------------------
- // Test nasal::String
- //----------------------------------------------------------------------------
-
- String string( to_nasal(c, "Test") );
- BOOST_CHECK_EQUAL( from_nasal<std::string>(c, string.get_naRef()), "Test" );
- BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") );
- BOOST_CHECK( string.starts_with(string) );
- BOOST_CHECK( string.starts_with(String(c, "T")) );
- BOOST_CHECK( string.starts_with(String(c, "Te")) );
- BOOST_CHECK( string.starts_with(String(c, "Tes")) );
- BOOST_CHECK( string.starts_with(String(c, "Test")) );
- BOOST_CHECK( !string.starts_with(String(c, "Test1")) );
- BOOST_CHECK( !string.starts_with(String(c, "bb")) );
- BOOST_CHECK( !string.starts_with(String(c, "bbasdasdafasd")) );
- BOOST_CHECK( string.ends_with(String(c, "t")) );
- BOOST_CHECK( string.ends_with(String(c, "st")) );
- BOOST_CHECK( string.ends_with(String(c, "est")) );
- BOOST_CHECK( string.ends_with(String(c, "Test")) );
- BOOST_CHECK( !string.ends_with(String(c, "1Test")) );
- BOOST_CHECK( !string.ends_with(String(c, "abc")) );
- BOOST_CHECK( !string.ends_with(String(c, "estasdasd")) );
- BOOST_CHECK_EQUAL( string.find('e'), 1 );
- BOOST_CHECK_EQUAL( string.find('9'), String::npos );
- BOOST_CHECK_EQUAL( string.find_first_of(String(c, "st")), 2 );
- BOOST_CHECK_EQUAL( string.find_first_of(String(c, "st"), 3), 3 );
- BOOST_CHECK_EQUAL( string.find_first_of(String(c, "xyz")), String::npos );
- BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tst")), 1 );
- BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tse"), 2), 3 );
- BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc")), 0 );
- BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc"), 20), String::npos );
-
- naFreeContext(c);
-}
+++ /dev/null
-#define BOOST_TEST_MODULE cppbind
-#include <BoostTestTargetConfig.h>
-
-#include "Ghost.hxx"
-#include "NasalContext.hxx"
-
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-class Base1:
- public virtual SGVirtualWeakReferenced
-{};
-
-class Base2:
- public virtual SGVirtualWeakReferenced
-{};
-
-class Derived:
- public Base1,
- public Base2
-{};
-
-typedef SGSharedPtr<Base1> Base1Ptr;
-typedef SGSharedPtr<Base2> Base2Ptr;
-typedef SGSharedPtr<Derived> DerivedPtr;
-typedef SGWeakPtr<Derived> DerivedWeakPtr;
-
-typedef SGSharedPtr<SGReferenced> SGReferencedPtr;
-
-// Check if shared_ptr_traits give correct types for strong and weak shared
-// pointer
-#define CHECK_PTR_TRAIT_TYPE(ptr_t, type_name, type)\
- BOOST_STATIC_ASSERT((boost::is_same<\
- nasal::shared_ptr_traits<ptr_t>::type_name,\
- type\
- >::value));
-
-#define CHECK_PTR_TRAIT(ref, weak)\
- CHECK_PTR_TRAIT_TYPE(ref, strong_ref, ref)\
- CHECK_PTR_TRAIT_TYPE(weak, weak_ref, weak)\
-
-CHECK_PTR_TRAIT(DerivedPtr, DerivedWeakPtr)
-CHECK_PTR_TRAIT(boost::shared_ptr<Base1>, boost::weak_ptr<Base1>)
-
-#undef CHECK_PTR_TRAIT
-#undef CHECK_PTR_TRAIT_TYPE
-
-BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base1Ptr>::value));
-BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base2Ptr>::value));
-BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedPtr>::value));
-BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedWeakPtr>::value));
-BOOST_STATIC_ASSERT((!nasal::supports_weak_ref<SGReferencedPtr>::value));
-
-static void setupGhosts()
-{
- nasal::Ghost<Base1Ptr>::init("Base1");
- nasal::Ghost<Base2Ptr>::init("Base2");
- nasal::Ghost<DerivedPtr>::init("Derived")
- .bases<Base1Ptr>()
- .bases<Base2Ptr>();
-}
-
-//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
-{
- setupGhosts();
- naContext c = naNewContext();
-
- DerivedPtr d = new Derived();
- DerivedWeakPtr weak(d);
-
- // store weak pointer and extract strong pointer
- naRef na_d = nasal::to_nasal(c, DerivedWeakPtr(d));
- BOOST_REQUIRE( naIsGhost(na_d) );
- BOOST_CHECK_EQUAL( nasal::from_nasal<Base1Ptr>(c, na_d), d );
- BOOST_CHECK_EQUAL( nasal::from_nasal<Base2Ptr>(c, na_d), d );
- BOOST_CHECK_EQUAL( nasal::from_nasal<DerivedPtr>(c, na_d), d );
-
- d.reset();
- BOOST_REQUIRE_THROW( nasal::from_nasal<DerivedPtr>(c, na_d),
- nasal::bad_nasal_cast );
-
- // store strong pointer and extract weak pointer
- d.reset(new Derived);
- na_d = nasal::to_nasal(c, d);
- BOOST_REQUIRE( naIsGhost(na_d) );
-
- weak = nasal::from_nasal<DerivedWeakPtr>(c, na_d);
- BOOST_CHECK_EQUAL( weak.lock(), d );
-
- d.reset();
- BOOST_REQUIRE( nasal::from_nasal<DerivedPtr>(c, na_d) );
- BOOST_REQUIRE( weak.lock() );
-
- naFreeContext(c);
- naGC();
- nasal::ghostProcessDestroyList();
-
- BOOST_REQUIRE( !weak.lock() );
-}
-
-//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( ghost_casting_storage )
-{
- setupGhosts();
- nasal::Context c;
-
- // Check converting to and from every class in the hierarchy for an instance
- // of the leaf class
- DerivedPtr d = new Derived();
-
- naRef na_d = nasal::to_nasal(c, d),
- na_b1 = nasal::to_nasal(c, Base1Ptr(d)),
- na_b2 = nasal::to_nasal(c, Base2Ptr(d));
-
- Derived *d0 = nasal::from_nasal<Derived*>(c, na_d),
- *d1 = nasal::from_nasal<Derived*>(c, na_b1),
- *d2 = nasal::from_nasal<Derived*>(c, na_b2);
-
- BOOST_CHECK_EQUAL(d0, d.get());
- BOOST_CHECK_EQUAL(d1, d.get());
- BOOST_CHECK_EQUAL(d2, d.get());
-
- Base1 *b1 = nasal::from_nasal<Base1*>(c, na_b1);
- BOOST_CHECK_EQUAL(b1, static_cast<Base1*>(d.get()));
-
- Base2 *b2 = nasal::from_nasal<Base2*>(c, na_b2);
- BOOST_CHECK_EQUAL(b2, static_cast<Base2*>(d.get()));
-
- // Check converting from base class instance to derived classes is not
- // possible
- Base1Ptr b1_ref = new Base1();
- na_b1 = nasal::to_nasal(c, b1_ref);
-
- BOOST_CHECK_EQUAL(nasal::from_nasal<Base1*>(c, na_b1), b1_ref.get());
- BOOST_CHECK_THROW(nasal::from_nasal<Base2*>(c, na_b1), nasal::bad_nasal_cast);
- BOOST_CHECK_THROW(nasal::from_nasal<Derived*>(c, na_b1), nasal::bad_nasal_cast);
-}
-
-//------------------------------------------------------------------------------
-#define CHECK_PTR_STORAGE_TRAIT_TYPE(ptr_t, storage)\
- BOOST_STATIC_ASSERT((boost::is_same<\
- nasal::shared_ptr_storage<ptr_t>::storage_type,\
- storage\
- >::value));
-
-CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedPtr, Derived)
-CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedWeakPtr, DerivedWeakPtr)
-
-typedef boost::shared_ptr<Derived> BoostDerivedPtr;
-CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedPtr, BoostDerivedPtr)
-
-typedef boost::weak_ptr<Derived> BoostDerivedWeakPtr;
-CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedWeakPtr, BoostDerivedWeakPtr)
-
-#undef CHECK_PTR_STORAGE_TRAIT_TYPE
-
-BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base1Ptr>::is_intrusive::value));
-BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base2Ptr>::is_intrusive::value));
-BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedPtr>::is_intrusive::value));
-BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedWeakPtr>::is_intrusive::value));
-BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<SGReferencedPtr>::is_intrusive::value));
-
-BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::shared_ptr<Derived> >::is_intrusive::value));
-BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::weak_ptr<Derived> >::is_intrusive::value));
-
-BOOST_AUTO_TEST_CASE( storage_traits )
-{
- DerivedPtr d = new Derived();
-
- Derived* d_raw = nasal::shared_ptr_storage<DerivedPtr>::ref(d);
- BOOST_REQUIRE_EQUAL(d_raw, d.get());
- BOOST_REQUIRE_EQUAL(d.getNumRefs(), 2);
-
- DerivedWeakPtr* d_weak = nasal::shared_ptr_storage<DerivedWeakPtr>::ref(d);
- BOOST_REQUIRE_EQUAL(
- nasal::shared_ptr_storage<DerivedWeakPtr>::get<Derived*>(d_weak),
- d_raw
- );
-
- d.reset();
- BOOST_REQUIRE_EQUAL(Derived::count(d_raw), 1);
-
- nasal::shared_ptr_storage<DerivedPtr>::unref(d_raw);
- BOOST_REQUIRE(d_weak->expired());
-
- nasal::shared_ptr_storage<DerivedWeakPtr>::unref(d_weak);
-}
+++ /dev/null
-#define BOOST_TEST_MODULE cppbind
-#include <BoostTestTargetConfig.h>
-
-#include "NasalCallContext.hxx"
-
-class TestContext:
- public nasal::CallContext
-{
- public:
- TestContext():
- CallContext(naNewContext(), naNil(), 0, 0)
- {}
-
- ~TestContext()
- {
- naFreeContext(c);
- }
-
- template<class T>
- T from_str(const std::string& str)
- {
- return from_nasal<T>(to_nasal(str));
- }
-
- naRef exec(const std::string& code_str, nasal::Me me)
- {
- int err_line = -1;
- naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 0,
- (char*)code_str.c_str(), code_str.length(),
- &err_line );
- if( !naIsCode(code) )
- throw std::runtime_error("Failed to parse code: " + code_str);
-
- return naCallMethod(code, me, 0, 0, naNil());
- }
-
- template<class T>
- T exec(const std::string& code)
- {
- return from_nasal<T>(exec(code, naNil()));
- }
-
- template<class T>
- T convert(const std::string& str)
- {
- return from_nasal<T>(to_nasal(str));
- }
-};
-
-static void runNumTests( double (TestContext::*test_double)(const std::string&),
- int (TestContext::*test_int)(const std::string&) )
-{
- TestContext c;
-
- BOOST_CHECK_CLOSE((c.*test_double)("0.5"), 0.5, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)(".6"), 0.6, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("-.7"), -0.7, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("-0.8"), -0.8, 1e-5);
- BOOST_CHECK_SMALL((c.*test_double)("0.0"), 1e-5);
- BOOST_CHECK_SMALL((c.*test_double)("-.0"), 1e-5);
-
- BOOST_CHECK_CLOSE((c.*test_double)("1.23e4"), 1.23e4, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("1.23e-4"), 1.23e-4, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("-1.23e4"), -1.23e4, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("-1.23e-4"), -1.23e-4, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("1e-4"), 1e-4, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_double)("-1e-4"), -1e-4, 1e-5);
-
- BOOST_CHECK_EQUAL((c.*test_int)("123"), 123);
- BOOST_CHECK_EQUAL((c.*test_int)("-958"), -958);
-
- BOOST_CHECK_CLOSE((c.*test_int)("-1e7"), -1e7, 1e-5);
- BOOST_CHECK_CLOSE((c.*test_int)("2E07"), 2e07, 1e-5);
-
- BOOST_CHECK_EQUAL((c.*test_int)("0755"), 755);
- BOOST_CHECK_EQUAL((c.*test_int)("0055"), 55);
- BOOST_CHECK_EQUAL((c.*test_int)("-0155"), -155);
-
- BOOST_CHECK_EQUAL((c.*test_int)("0o755"), 0755);
- BOOST_CHECK_EQUAL((c.*test_int)("0o055"), 055);
- BOOST_CHECK_EQUAL((c.*test_int)("-0o155"), -0155);
-
- BOOST_CHECK_EQUAL((c.*test_int)("0x755"), 0x755);
- BOOST_CHECK_EQUAL((c.*test_int)("0x055"), 0x55);
- BOOST_CHECK_EQUAL((c.*test_int)("-0x155"), -0x155);
-}
-
-BOOST_AUTO_TEST_CASE( parse_num )
-{
- runNumTests(&TestContext::convert<double>, &TestContext::convert<int>);
-}
-
-BOOST_AUTO_TEST_CASE( lex_num )
-{
- runNumTests(&TestContext::exec<double>, &TestContext::exec<int>);
-}
--- /dev/null
+///@file
+/// Nasal context for testing and executing code
+///
+// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef SG_NASAL_TESTCONTEXT_HXX_
+#define SG_NASAL_TESTCONTEXT_HXX_
+
+#include <simgear/nasal/cppbind/NasalCallContext.hxx>
+
+class TestContext:
+ public nasal::CallContext
+{
+ public:
+ TestContext():
+ CallContext(naNewContext(), naNil(), 0, 0)
+ {}
+
+ ~TestContext()
+ {
+ naFreeContext(c);
+ }
+
+ void runGC()
+ {
+ naFreeContext(c);
+ naGC();
+ c = naNewContext();
+ }
+
+ template<class T>
+ T from_str(const std::string& str)
+ {
+ return from_nasal<T>(to_nasal(str));
+ }
+
+ naRef exec(const std::string& code_str, nasal::Me me)
+ {
+ int err_line = -1;
+ naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 0,
+ (char*)code_str.c_str(), code_str.length(),
+ &err_line );
+ if( !naIsCode(code) )
+ throw std::runtime_error("Failed to parse code: " + code_str);
+
+ return naCallMethod(code, me, 0, 0, naNil());
+ }
+
+ template<class T>
+ T exec(const std::string& code)
+ {
+ return from_nasal<T>(exec(code, naNil()));
+ }
+
+ template<class T>
+ T convert(const std::string& str)
+ {
+ return from_nasal<T>(to_nasal(str));
+ }
+};
+
+#endif /* SG_NASAL_TESTCONTEXT_HXX_ */
--- /dev/null
+#define BOOST_TEST_MODULE cppbind
+#include <BoostTestTargetConfig.h>
+
+#include <simgear/nasal/cppbind/Ghost.hxx>
+#include <simgear/nasal/cppbind/NasalHash.hxx>
+#include <simgear/nasal/cppbind/NasalString.hxx>
+#include <simgear/math/SGMath.hxx>
+#include <simgear/structure/map.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <cstring>
+
+enum MyEnum
+{
+ ENUM_FIRST,
+ ENUM_ANOTHER,
+ ENUM_LAST
+};
+struct Base
+{
+ naRef member(const nasal::CallContext&) { return naNil(); }
+ virtual ~Base(){};
+
+ std::string getString() const { return ""; }
+ void setString(const std::string&) {}
+ void constVoidFunc() const {}
+ size_t test1Arg(const std::string& str) const { return str.length(); }
+ bool test2Args(const std::string& s, bool c) { return c && s.empty(); }
+
+ std::string var;
+ const std::string& getVar() const { return var; }
+ 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";
+ }
+ bool genericGet(const std::string& key, std::string& val_out) const
+ {
+ if( key != "get_test" )
+ return false;
+
+ val_out = "generic-get";
+ return true;
+ }
+};
+
+void baseVoidFunc(Base& b) {}
+void baseConstVoidFunc(const Base& b) {}
+size_t baseFunc2Args(Base& b, int x, const std::string& s) { return x + s.size(); }
+std::string testPtr(Base& b) { return b.getString(); }
+void baseFuncCallContext(const Base&, const nasal::CallContext&) {}
+
+struct Derived:
+ public Base
+{
+ int _x;
+ int getX() const { return _x; }
+ void setX(int x) { _x = x; }
+};
+
+naRef f_derivedGetRandom(const Derived&, naContext)
+{
+ return naNil();
+}
+void f_derivedSetX(Derived& d, naContext, naRef r)
+{
+ d._x = static_cast<int>(naNumValue(r).num);
+}
+
+struct DoubleDerived:
+ public Derived
+{
+
+};
+
+typedef boost::shared_ptr<Base> BasePtr;
+typedef std::vector<BasePtr> BaseVec;
+
+struct DoubleDerived2:
+ public Derived
+{
+ const BasePtr& getBase() const{return _base;}
+ BasePtr _base;
+ BaseVec doSomeBaseWork(const BaseVec& v) { return v; }
+};
+
+class SGReferenceBasedClass:
+ public SGReferenced
+{
+
+};
+
+class SGWeakReferenceBasedClass:
+ public SGWeakReferenced
+{
+
+};
+
+typedef boost::shared_ptr<Derived> DerivedPtr;
+typedef boost::shared_ptr<DoubleDerived> DoubleDerivedPtr;
+typedef boost::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
+typedef SGSharedPtr<SGReferenceBasedClass> SGRefBasedPtr;
+typedef SGSharedPtr<SGWeakReferenceBasedClass> SGWeakRefBasedPtr;
+
+typedef boost::weak_ptr<Derived> DerivedWeakPtr;
+
+naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); }
+naRef f_derivedGetX(const Derived& d, naContext c)
+{
+ return nasal::to_nasal(c, d.getX());
+}
+naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
+
+BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
+{
+ naContext c = naNewContext();
+ naRef r;
+
+ using namespace nasal;
+
+ r = to_nasal(c, ENUM_ANOTHER);
+ BOOST_CHECK_EQUAL(from_nasal<int>(c, r), ENUM_ANOTHER);
+
+ r = to_nasal(c, "Test");
+ BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
+ BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
+
+ r = to_nasal(c, std::string("Test"));
+ BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
+ BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
+
+ r = to_nasal(c, 42);
+ BOOST_CHECK_EQUAL(naNumValue(r).num, 42);
+ BOOST_CHECK_EQUAL(from_nasal<int>(c, r), 42);
+
+ r = to_nasal(c, 4.2f);
+ BOOST_CHECK_EQUAL(naNumValue(r).num, 4.2f);
+ BOOST_CHECK_EQUAL(from_nasal<float>(c, r), 4.2f);
+
+ float test_data[3] = {0, 4, 2};
+ r = to_nasal(c, test_data);
+
+ SGVec2f vec(0,2);
+ r = to_nasal(c, vec);
+ BOOST_CHECK_EQUAL(from_nasal<SGVec2f>(c, r), vec);
+
+ std::vector<int> std_vec;
+ r = to_nasal(c, std_vec);
+
+ r = to_nasal(c, "string");
+ BOOST_CHECK_THROW(from_nasal<int>(c, r), bad_nasal_cast);
+
+ Hash hash(c);
+ hash.set("vec", r);
+ hash.set("vec2", vec);
+ hash.set("name", "my-name");
+ hash.set("string", std::string("blub"));
+ hash.set("func", &f_freeFunction);
+
+ BOOST_CHECK_EQUAL(hash.size(), 5);
+ for(Hash::const_iterator it = hash.begin(); it != hash.end(); ++it)
+ BOOST_CHECK_EQUAL( hash.get<std::string>(it->getKey()),
+ it->getValue<std::string>() );
+
+ Hash::iterator it1, it2;
+ Hash::const_iterator it3 = it1, it4(it2);
+ it1 = it2;
+ it3 = it2;
+
+ r = to_nasal(c, hash);
+ BOOST_REQUIRE( naIsHash(r) );
+
+ simgear::StringMap string_map = from_nasal<simgear::StringMap>(c, r);
+ BOOST_CHECK_EQUAL(string_map.at("vec"), "string");
+ BOOST_CHECK_EQUAL(string_map.at("name"), "my-name");
+ BOOST_CHECK_EQUAL(string_map.at("string"), "blub");
+
+ BOOST_CHECK_EQUAL(hash.get<std::string>("name"), "my-name");
+ BOOST_CHECK(naIsString(hash.get("name")));
+
+ Hash mod = hash.createHash("mod");
+ mod.set("parent", hash);
+
+
+ // 'func' is a C++ function registered to Nasal and now converted back to C++
+ boost::function<int (int)> f = hash.get<int (int)>("func");
+ BOOST_REQUIRE( f );
+ BOOST_CHECK_EQUAL(f(3), 3);
+
+ boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
+ BOOST_REQUIRE( fs );
+ BOOST_CHECK_EQUAL(fs(14), "14");
+
+ typedef boost::function<void (int)> FuncVoidInt;
+ FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
+ BOOST_REQUIRE( fvi );
+ fvi(123);
+
+ typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
+ FuncMultiArg fma = hash.get<FuncMultiArg>("func");
+ BOOST_REQUIRE( fma );
+ BOOST_CHECK_EQUAL(fma("test", 3, .5), "test");
+
+ typedef boost::function<naRef (naRef)> naRefMemFunc;
+ naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
+ BOOST_REQUIRE( fmem );
+ naRef ret = fmem(hash.get_naRef()),
+ hash_ref = hash.get_naRef();
+ BOOST_CHECK( naIsIdentical(ret, hash_ref) );
+
+ // Check if nasal::Me gets passed as self/me and remaining arguments are
+ // passed on to function
+ typedef boost::function<int (Me, int)> MeIntFunc;
+ MeIntFunc fmeint = hash.get<MeIntFunc>("func");
+ BOOST_CHECK_EQUAL(fmeint(naNil(), 5), 5);
+
+ //----------------------------------------------------------------------------
+ // Test exposing classes to Nasal
+ //----------------------------------------------------------------------------
+
+ Ghost<BasePtr>::init("BasePtr")
+ .method("member", &Base::member)
+ .method("strlen", &Base::test1Arg)
+ .member("str", &Base::getString, &Base::setString)
+ .method("str_m", &Base::getString)
+ .method("void", &Base::constVoidFunc)
+ .member("var_r", &Base::getVar)
+ .member("var_w", &Base::setVar)
+ .member("var", &Base::getVar, &Base::setVar)
+ .method("void", &baseVoidFunc)
+ .method("void_c", &baseConstVoidFunc)
+ .method("int2args", &baseFunc2Args)
+ .method("bool2args", &Base::test2Args)
+ .method("str_ptr", &testPtr)
+ .method("this", &Base::getThis)
+ ._set(&Base::genericSet)
+ ._get(&Base::genericGet);
+ Ghost<DerivedPtr>::init("DerivedPtr")
+ .bases<BasePtr>()
+ .member("x", &Derived::getX, &Derived::setX)
+ .member("x_alternate", &f_derivedGetX)
+ .member("x_mixed", &f_derivedGetRandom, &Derived::setX)
+ .member("x_mixed2", &Derived::getX, &f_derivedSetX)
+ .member("x_w", &f_derivedSetX)
+ .method("free_fn", &derivedFreeMember)
+ .method("free_member", &derivedFreeMember)
+ .method("baseDoIt", &baseFuncCallContext);
+ Ghost<DoubleDerivedPtr>::init("DoubleDerivedPtr")
+ .bases<DerivedPtr>();
+ Ghost<DoubleDerived2Ptr>::init("DoubleDerived2Ptr")
+ .bases< Ghost<DerivedPtr> >()
+ .member("base", &DoubleDerived2::getBase)
+ .method("doIt", &DoubleDerived2::doSomeBaseWork);
+
+ Ghost<SGRefBasedPtr>::init("SGRefBasedPtr");
+ Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
+
+ SGWeakRefBasedPtr weak_ptr(new SGWeakReferenceBasedClass());
+ naRef nasal_ref = to_nasal(c, weak_ptr),
+ nasal_ptr = to_nasal(c, weak_ptr.get());
+
+ BOOST_REQUIRE( naIsGhost(nasal_ref) );
+ BOOST_REQUIRE( naIsGhost(nasal_ptr) );
+
+ SGWeakRefBasedPtr ptr1 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ref),
+ ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
+
+ BOOST_CHECK_EQUAL(weak_ptr, ptr1);
+ BOOST_CHECK_EQUAL(weak_ptr, ptr2);
+
+
+ BOOST_REQUIRE( Ghost<BasePtr>::isInit() );
+ nasal::to_nasal(c, DoubleDerived2Ptr());
+
+ BasePtr d( new Derived );
+ naRef derived = to_nasal(c, d);
+ BOOST_REQUIRE( naIsGhost(derived) );
+ BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name );
+
+ // Get member function from ghost...
+ naRef thisGetter = naNil();
+ BOOST_CHECK( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
+ BOOST_CHECK( naIsFunc(thisGetter) );
+
+ // ...and check if it really gets passed the correct instance
+ typedef boost::function<unsigned long (Me)> MemFunc;
+ MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
+ BOOST_REQUIRE( fGetThis );
+ BOOST_CHECK_EQUAL( fGetThis(derived), (unsigned long)d.get() );
+
+ BasePtr d2( new DoubleDerived );
+ derived = to_nasal(c, d2);
+ BOOST_CHECK( naIsGhost(derived) );
+ BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"),
+ naGhost_type(derived)->name );
+
+ BasePtr d3( new DoubleDerived2 );
+ derived = to_nasal(c, d3);
+ BOOST_CHECK( naIsGhost(derived) );
+ BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"),
+ naGhost_type(derived)->name );
+
+ SGRefBasedPtr ref_based( new SGReferenceBasedClass );
+ naRef na_ref_based = to_nasal(c, ref_based.get());
+ BOOST_CHECK( naIsGhost(na_ref_based) );
+ BOOST_CHECK_EQUAL( from_nasal<SGReferenceBasedClass*>(c, na_ref_based),
+ ref_based.get() );
+ BOOST_CHECK_EQUAL( from_nasal<SGRefBasedPtr>(c, na_ref_based), ref_based );
+
+ BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived), d3 );
+ BOOST_CHECK_NE( from_nasal<BasePtr>(c, derived), d2 );
+ BOOST_CHECK_EQUAL( from_nasal<DerivedPtr>(c, derived),
+ boost::dynamic_pointer_cast<Derived>(d3) );
+ BOOST_CHECK_EQUAL( from_nasal<DoubleDerived2Ptr>(c, derived),
+ boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
+ BOOST_CHECK_THROW( from_nasal<DoubleDerivedPtr>(c, derived), bad_nasal_cast );
+
+ std::map<std::string, BasePtr> instances;
+ BOOST_CHECK( naIsHash(to_nasal(c, instances)) );
+
+ std::map<std::string, DerivedPtr> instances_d;
+ BOOST_CHECK( naIsHash(to_nasal(c, instances_d)) );
+
+ std::map<std::string, int> int_map;
+ BOOST_CHECK( naIsHash(to_nasal(c, int_map)) );
+
+ std::map<std::string, std::vector<int> > int_vector_map;
+ BOOST_CHECK( naIsHash(to_nasal(c, int_vector_map)) );
+
+ simgear::StringMap dict =
+ simgear::StringMap("hello", "value")
+ ("key2", "value2");
+ naRef na_dict = to_nasal(c, dict);
+ BOOST_REQUIRE( naIsHash(na_dict) );
+ BOOST_CHECK_EQUAL( Hash(na_dict, c).get<std::string>("key2"), "value2" );
+
+ // Check converting to Ghost if using Nasal hashes with actual ghost inside
+ // the hashes parents vector
+ std::vector<naRef> parents;
+ parents.push_back(hash.get_naRef());
+ parents.push_back(derived);
+
+ Hash obj(c);
+ obj.set("parents", parents);
+ BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, obj.get_naRef()), d3 );
+
+ // Check recursive parents (aka parent-of-parent)
+ std::vector<naRef> parents2;
+ parents2.push_back(obj.get_naRef());
+ Hash derived_obj(c);
+ derived_obj.set("parents", parents2);
+ BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived_obj.get_naRef()), d3 );
+
+ std::vector<naRef> nasal_objects;
+ nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
+ nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d2) );
+ nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
+ naRef obj_vec = to_nasal(c, nasal_objects);
+
+ std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
+ BOOST_CHECK_EQUAL( objects[0], d );
+ BOOST_CHECK_EQUAL( objects[1], d2 );
+ BOOST_CHECK_EQUAL( 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());
+
+ BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
+ // always return 0...
+ BOOST_CHECK_EQUAL( 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());
+
+ BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
+ // always return 0...
+ BOOST_CHECK_EQUAL( from_nasal<std::string>(c, ret), "generic-get" );
+ }
+
+ //----------------------------------------------------------------------------
+ // Test nasal::CallContext
+ //----------------------------------------------------------------------------
+
+
+ int int_vec[] = {1,2,3};
+ std::map<std::string, std::string> map;
+ naRef args[] = {
+ to_nasal(c, std::string("test-arg")),
+ to_nasal(c, 4),
+ to_nasal(c, int_vec),
+ to_nasal(c, map)
+ };
+ CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args);
+ BOOST_CHECK_EQUAL( cc.requireArg<std::string>(0), "test-arg" );
+ BOOST_CHECK_EQUAL( cc.getArg<std::string>(0), "test-arg" );
+ BOOST_CHECK_EQUAL( cc.getArg<std::string>(10), "" );
+ BOOST_CHECK( cc.isString(0) );
+ BOOST_CHECK( !cc.isNumeric(0) );
+ BOOST_CHECK( !cc.isVector(0) );
+ BOOST_CHECK( !cc.isHash(0) );
+ BOOST_CHECK( !cc.isGhost(0) );
+ BOOST_CHECK( cc.isNumeric(1) );
+ BOOST_CHECK( cc.isVector(2) );
+ BOOST_CHECK( cc.isHash(3) );
+
+ naRef args_vec = nasal::to_nasal(c, args);
+ BOOST_CHECK( naIsVector(args_vec) );
+
+ //----------------------------------------------------------------------------
+ // Test nasal::String
+ //----------------------------------------------------------------------------
+
+ String string( to_nasal(c, "Test") );
+ BOOST_CHECK_EQUAL( from_nasal<std::string>(c, string.get_naRef()), "Test" );
+ BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") );
+ BOOST_CHECK( string.starts_with(string) );
+ BOOST_CHECK( string.starts_with(String(c, "T")) );
+ BOOST_CHECK( string.starts_with(String(c, "Te")) );
+ BOOST_CHECK( string.starts_with(String(c, "Tes")) );
+ BOOST_CHECK( string.starts_with(String(c, "Test")) );
+ BOOST_CHECK( !string.starts_with(String(c, "Test1")) );
+ BOOST_CHECK( !string.starts_with(String(c, "bb")) );
+ BOOST_CHECK( !string.starts_with(String(c, "bbasdasdafasd")) );
+ BOOST_CHECK( string.ends_with(String(c, "t")) );
+ BOOST_CHECK( string.ends_with(String(c, "st")) );
+ BOOST_CHECK( string.ends_with(String(c, "est")) );
+ BOOST_CHECK( string.ends_with(String(c, "Test")) );
+ BOOST_CHECK( !string.ends_with(String(c, "1Test")) );
+ BOOST_CHECK( !string.ends_with(String(c, "abc")) );
+ BOOST_CHECK( !string.ends_with(String(c, "estasdasd")) );
+ BOOST_CHECK_EQUAL( string.find('e'), 1 );
+ BOOST_CHECK_EQUAL( string.find('9'), String::npos );
+ BOOST_CHECK_EQUAL( string.find_first_of(String(c, "st")), 2 );
+ BOOST_CHECK_EQUAL( string.find_first_of(String(c, "st"), 3), 3 );
+ BOOST_CHECK_EQUAL( string.find_first_of(String(c, "xyz")), String::npos );
+ BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tst")), 1 );
+ BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tse"), 2), 3 );
+ BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc")), 0 );
+ BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc"), 20), String::npos );
+
+ naFreeContext(c);
+}
--- /dev/null
+#define BOOST_TEST_MODULE cppbind
+#include <BoostTestTargetConfig.h>
+
+#include <simgear/nasal/cppbind/Ghost.hxx>
+#include <simgear/nasal/cppbind/NasalContext.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+class Base1:
+ public virtual SGVirtualWeakReferenced
+{};
+
+class Base2:
+ public virtual SGVirtualWeakReferenced
+{};
+
+class Derived:
+ public Base1,
+ public Base2
+{};
+
+typedef SGSharedPtr<Base1> Base1Ptr;
+typedef SGSharedPtr<Base2> Base2Ptr;
+typedef SGSharedPtr<Derived> DerivedPtr;
+typedef SGWeakPtr<Derived> DerivedWeakPtr;
+
+typedef SGSharedPtr<SGReferenced> SGReferencedPtr;
+
+// Check if shared_ptr_traits give correct types for strong and weak shared
+// pointer
+#define CHECK_PTR_TRAIT_TYPE(ptr_t, type_name, type)\
+ BOOST_STATIC_ASSERT((boost::is_same<\
+ nasal::shared_ptr_traits<ptr_t>::type_name,\
+ type\
+ >::value));
+
+#define CHECK_PTR_TRAIT(ref, weak)\
+ CHECK_PTR_TRAIT_TYPE(ref, strong_ref, ref)\
+ CHECK_PTR_TRAIT_TYPE(weak, weak_ref, weak)\
+
+CHECK_PTR_TRAIT(DerivedPtr, DerivedWeakPtr)
+CHECK_PTR_TRAIT(boost::shared_ptr<Base1>, boost::weak_ptr<Base1>)
+
+#undef CHECK_PTR_TRAIT
+#undef CHECK_PTR_TRAIT_TYPE
+
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base1Ptr>::value));
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base2Ptr>::value));
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedPtr>::value));
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedWeakPtr>::value));
+BOOST_STATIC_ASSERT((!nasal::supports_weak_ref<SGReferencedPtr>::value));
+
+static void setupGhosts()
+{
+ nasal::Ghost<Base1Ptr>::init("Base1");
+ nasal::Ghost<Base2Ptr>::init("Base2");
+ nasal::Ghost<DerivedPtr>::init("Derived")
+ .bases<Base1Ptr>()
+ .bases<Base2Ptr>();
+}
+
+//------------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
+{
+ setupGhosts();
+ naContext c = naNewContext();
+
+ DerivedPtr d = new Derived();
+ DerivedWeakPtr weak(d);
+
+ // store weak pointer and extract strong pointer
+ naRef na_d = nasal::to_nasal(c, DerivedWeakPtr(d));
+ BOOST_REQUIRE( naIsGhost(na_d) );
+ BOOST_CHECK_EQUAL( nasal::from_nasal<Base1Ptr>(c, na_d), d );
+ BOOST_CHECK_EQUAL( nasal::from_nasal<Base2Ptr>(c, na_d), d );
+ BOOST_CHECK_EQUAL( nasal::from_nasal<DerivedPtr>(c, na_d), d );
+
+ d.reset();
+ BOOST_REQUIRE_THROW( nasal::from_nasal<DerivedPtr>(c, na_d),
+ nasal::bad_nasal_cast );
+
+ // store strong pointer and extract weak pointer
+ d.reset(new Derived);
+ na_d = nasal::to_nasal(c, d);
+ BOOST_REQUIRE( naIsGhost(na_d) );
+
+ weak = nasal::from_nasal<DerivedWeakPtr>(c, na_d);
+ BOOST_CHECK_EQUAL( weak.lock(), d );
+
+ d.reset();
+ BOOST_REQUIRE( nasal::from_nasal<DerivedPtr>(c, na_d) );
+ BOOST_REQUIRE( weak.lock() );
+
+ naFreeContext(c);
+ naGC();
+ nasal::ghostProcessDestroyList();
+
+ BOOST_REQUIRE( !weak.lock() );
+}
+
+//------------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE( ghost_casting_storage )
+{
+ setupGhosts();
+ nasal::Context c;
+
+ // Check converting to and from every class in the hierarchy for an instance
+ // of the leaf class
+ DerivedPtr d = new Derived();
+
+ naRef na_d = nasal::to_nasal(c, d),
+ na_b1 = nasal::to_nasal(c, Base1Ptr(d)),
+ na_b2 = nasal::to_nasal(c, Base2Ptr(d));
+
+ Derived *d0 = nasal::from_nasal<Derived*>(c, na_d),
+ *d1 = nasal::from_nasal<Derived*>(c, na_b1),
+ *d2 = nasal::from_nasal<Derived*>(c, na_b2);
+
+ BOOST_CHECK_EQUAL(d0, d.get());
+ BOOST_CHECK_EQUAL(d1, d.get());
+ BOOST_CHECK_EQUAL(d2, d.get());
+
+ Base1 *b1 = nasal::from_nasal<Base1*>(c, na_b1);
+ BOOST_CHECK_EQUAL(b1, static_cast<Base1*>(d.get()));
+
+ Base2 *b2 = nasal::from_nasal<Base2*>(c, na_b2);
+ BOOST_CHECK_EQUAL(b2, static_cast<Base2*>(d.get()));
+
+ // Check converting from base class instance to derived classes is not
+ // possible
+ Base1Ptr b1_ref = new Base1();
+ na_b1 = nasal::to_nasal(c, b1_ref);
+
+ BOOST_CHECK_EQUAL(nasal::from_nasal<Base1*>(c, na_b1), b1_ref.get());
+ BOOST_CHECK_THROW(nasal::from_nasal<Base2*>(c, na_b1), nasal::bad_nasal_cast);
+ BOOST_CHECK_THROW(nasal::from_nasal<Derived*>(c, na_b1), nasal::bad_nasal_cast);
+}
+
+//------------------------------------------------------------------------------
+#define CHECK_PTR_STORAGE_TRAIT_TYPE(ptr_t, storage)\
+ BOOST_STATIC_ASSERT((boost::is_same<\
+ nasal::shared_ptr_storage<ptr_t>::storage_type,\
+ storage\
+ >::value));
+
+CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedPtr, Derived)
+CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedWeakPtr, DerivedWeakPtr)
+
+typedef boost::shared_ptr<Derived> BoostDerivedPtr;
+CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedPtr, BoostDerivedPtr)
+
+typedef boost::weak_ptr<Derived> BoostDerivedWeakPtr;
+CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedWeakPtr, BoostDerivedWeakPtr)
+
+#undef CHECK_PTR_STORAGE_TRAIT_TYPE
+
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base1Ptr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base2Ptr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedPtr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedWeakPtr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<SGReferencedPtr>::is_intrusive::value));
+
+BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::shared_ptr<Derived> >::is_intrusive::value));
+BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::weak_ptr<Derived> >::is_intrusive::value));
+
+BOOST_AUTO_TEST_CASE( storage_traits )
+{
+ DerivedPtr d = new Derived();
+
+ Derived* d_raw = nasal::shared_ptr_storage<DerivedPtr>::ref(d);
+ BOOST_REQUIRE_EQUAL(d_raw, d.get());
+ BOOST_REQUIRE_EQUAL(d.getNumRefs(), 2);
+
+ DerivedWeakPtr* d_weak = nasal::shared_ptr_storage<DerivedWeakPtr>::ref(d);
+ BOOST_REQUIRE_EQUAL(
+ nasal::shared_ptr_storage<DerivedWeakPtr>::get<Derived*>(d_weak),
+ d_raw
+ );
+
+ d.reset();
+ BOOST_REQUIRE_EQUAL(Derived::count(d_raw), 1);
+
+ nasal::shared_ptr_storage<DerivedPtr>::unref(d_raw);
+ BOOST_REQUIRE(d_weak->expired());
+
+ nasal::shared_ptr_storage<DerivedWeakPtr>::unref(d_weak);
+}
--- /dev/null
+#define BOOST_TEST_MODULE nasal
+#include <BoostTestTargetConfig.h>
+
+#include "TestContext.hxx"
+#include <iostream>
+#include <set>
+
+static std::set<intptr_t> active_instances;
+
+static void ghost_destroy(void* p)
+{
+ active_instances.erase((intptr_t)p);
+}
+
+static naGhostType ghost_type = {
+ &ghost_destroy,
+ "TestGhost",
+ 0, // get_member
+ 0 // set_member
+};
+
+static naRef createTestGhost(TestContext& c, intptr_t p)
+{
+ active_instances.insert(p);
+ return naNewGhost(c.c, &ghost_type, (void*)p);
+}
+
+//------------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE( ghost_gc )
+{
+ TestContext c;
+ BOOST_REQUIRE(active_instances.empty());
+
+ //-----------------------------------------------
+ // Just create ghosts and let the gc destroy them
+
+ naRef g1 = createTestGhost(c, 1),
+ g2 = createTestGhost(c, 2);
+
+ BOOST_CHECK_EQUAL(active_instances.count(1), 1);
+ BOOST_CHECK_EQUAL(active_instances.count(2), 1);
+ BOOST_CHECK_EQUAL(active_instances.size(), 2);
+
+ c.runGC();
+
+ BOOST_REQUIRE(active_instances.empty());
+
+
+ //-----------------------------------------------
+ // Create some more ghosts and save one instance
+ // from being garbage collected.
+
+ g1 = createTestGhost(c, 1);
+ g2 = createTestGhost(c, 2);
+
+ int gc1 = naGCSave(g1);
+ c.runGC();
+
+ BOOST_CHECK_EQUAL(active_instances.count(1), 1);
+ BOOST_CHECK_EQUAL(active_instances.size(), 1);
+
+ naGCRelease(gc1);
+ c.runGC();
+
+ BOOST_REQUIRE(active_instances.empty());
+
+
+ //-----------------------------------------------
+ // Now test attaching one ghost to another
+
+ g1 = createTestGhost(c, 1);
+ g2 = createTestGhost(c, 2);
+
+ gc1 = naGCSave(g1);
+ naGhost_setData(g1, g2); // bind lifetime of g2 to g1...
+
+ c.runGC();
+
+ BOOST_CHECK_EQUAL(active_instances.count(1), 1);
+ BOOST_CHECK_EQUAL(active_instances.count(2), 1);
+ BOOST_CHECK_EQUAL(active_instances.size(), 2);
+
+ naGhost_setData(g1, naNil()); // cut connection
+ c.runGC();
+
+ BOOST_CHECK_EQUAL(active_instances.count(1), 1);
+ BOOST_CHECK_EQUAL(active_instances.size(), 1);
+
+ naGCRelease(gc1);
+ c.runGC();
+
+ BOOST_REQUIRE(active_instances.empty());
+}
--- /dev/null
+#define BOOST_TEST_MODULE nasal
+#include <BoostTestTargetConfig.h>
+
+#include "TestContext.hxx"
+
+static void runNumTests( double (TestContext::*test_double)(const std::string&),
+ int (TestContext::*test_int)(const std::string&) )
+{
+ TestContext c;
+
+ BOOST_CHECK_CLOSE((c.*test_double)("0.5"), 0.5, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)(".6"), 0.6, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-.7"), -0.7, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-0.8"), -0.8, 1e-5);
+ BOOST_CHECK_SMALL((c.*test_double)("0.0"), 1e-5);
+ BOOST_CHECK_SMALL((c.*test_double)("-.0"), 1e-5);
+
+ BOOST_CHECK_CLOSE((c.*test_double)("1.23e4"), 1.23e4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("1.23e-4"), 1.23e-4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-1.23e4"), -1.23e4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-1.23e-4"), -1.23e-4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("1e-4"), 1e-4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-1e-4"), -1e-4, 1e-5);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("123"), 123);
+ BOOST_CHECK_EQUAL((c.*test_int)("-958"), -958);
+
+ BOOST_CHECK_CLOSE((c.*test_int)("-1e7"), -1e7, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_int)("2E07"), 2e07, 1e-5);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("0755"), 755);
+ BOOST_CHECK_EQUAL((c.*test_int)("0055"), 55);
+ BOOST_CHECK_EQUAL((c.*test_int)("-0155"), -155);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("0o755"), 0755);
+ BOOST_CHECK_EQUAL((c.*test_int)("0o055"), 055);
+ BOOST_CHECK_EQUAL((c.*test_int)("-0o155"), -0155);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("0x755"), 0x755);
+ BOOST_CHECK_EQUAL((c.*test_int)("0x055"), 0x55);
+ BOOST_CHECK_EQUAL((c.*test_int)("-0x155"), -0x155);
+}
+
+BOOST_AUTO_TEST_CASE( parse_num )
+{
+ runNumTests(&TestContext::convert<double>, &TestContext::convert<int>);
+}
+
+BOOST_AUTO_TEST_CASE( lex_num )
+{
+ runNumTests(&TestContext::exec<double>, &TestContext::exec<int>);
+}
GC_HEADER;
naGhostType* gtype;
void* ptr;
+ naRef data; //!< Nasal data bound to the lifetime of the ghost.
};
struct naPool {
newb->next = p->blocks;
p->blocks = newb;
naBZero(newb->block, need * p->elemsz);
-
+
if(need > p->freesz - p->freetop) need = p->freesz - p->freetop;
p->nfree = 0;
p->free = p->free0 + p->freetop;
mark(PTR(r).func->namespace);
mark(PTR(r).func->next);
break;
+ case T_GHOST:
+ mark(PTR(r).ghost->data);
+ break;
}
}
// allocs of this type until the next collection
globals->allocCount += total/2;
-
+
// Allocate more if necessary (try to keep 25-50% of the objects
// available)
if(p->nfree < total/4) {
// ensure 'simple' ghost users don't see garbage for these fields
type->get_member = 0;
type->set_member = 0;
-
+
ghost = naNew(c, T_GHOST);
PTR(ghost).ghost->gtype = type;
PTR(ghost).ghost->ptr = ptr;
+ PTR(ghost).ghost->data = naNil();
return ghost;
}
naRef ghost = naNew(c, T_GHOST);
PTR(ghost).ghost->gtype = t;
PTR(ghost).ghost->ptr = ptr;
+ PTR(ghost).ghost->data = naNil();
return ghost;
}
return PTR(ghost).ghost->ptr;
}
+void naGhost_setData(naRef ghost, naRef data)
+{
+ if(IS_GHOST(ghost))
+ PTR(ghost).ghost->data = data;
+}
+
+naRef naGhost_data(naRef ghost)
+{
+ if(!IS_GHOST(ghost)) return naNil();
+ return PTR(ghost).ghost->data;
+}
+
naRef naNil()
{
- naRef r;
+ naRef r;
SETPTR(r, 0);
return r;
}
naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
naGhostType* naGhost_type(naRef ghost);
void* naGhost_ptr(naRef ghost);
+/**
+ * Attach a nasal object to the given ghost. Binds the lifetime of @a data to
+ * the lifetime of the @a ghost.
+ */
+void naGhost_setData(naRef ghost, naRef data);
+/**
+ * Retrieve the object attached to the @a ghost, previously set with
+ * naGhost_setData().
+ */
+naRef naGhost_data(naRef ghost);
int naIsGhost(naRef r);
// Acquires a "modification lock" on a context, allowing the C code to