Ghost.hxx
NasalCallContext.hxx
NasalHash.hxx
+ NasalObjectHolder.hxx
NasalString.hxx
from_nasal.hxx
to_nasal.hxx
)
set(DETAIL_HEADERS
+ detail/from_nasal_function_templates.hxx
detail/from_nasal_helper.hxx
detail/functor_templates.hxx
detail/nasal_traits.hxx
set(SOURCES
NasalHash.cxx
+ NasalObjectHolder.cxx
NasalString.cxx
detail/from_nasal_helper.cxx
detail/to_nasal_helper.cxx
return from_nasal<T>(_context, get(name));
}
+ /**
+ * Get member converted to callable object
+ *
+ * @tparam Sig Function signature
+ * @param name Member name
+ */
+ template<class Sig>
+ typename boost::enable_if< boost::is_function<Sig>,
+ boost::function<Sig>
+ >::type
+ get(const std::string& name)
+ {
+ return from_nasal_helper(_context, get(name), static_cast<Sig*>(0));
+ }
+
/**
* Create a new child hash (module)
*
--- /dev/null
+// Wrapper class for keeping Nasal objects save from the garbage collector
+//
+// Copyright (C) 2013 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
+
+#include "NasalObjectHolder.hxx"
+#include <simgear/nasal/nasal.h>
+
+namespace nasal
+{
+
+ //----------------------------------------------------------------------------
+ ObjectHolder::~ObjectHolder()
+ {
+ naGCRelease(_gc_key);
+ }
+
+ //----------------------------------------------------------------------------
+ naRef ObjectHolder::get_naRef() const
+ {
+ return _ref;
+ }
+
+ //----------------------------------------------------------------------------
+ SGSharedPtr<ObjectHolder> ObjectHolder::makeShared(naRef obj)
+ {
+ return new ObjectHolder(obj);
+ }
+
+ //----------------------------------------------------------------------------
+ ObjectHolder::ObjectHolder(naRef obj):
+ _ref(obj),
+ _gc_key(naGCSave(obj))
+ {
+
+ }
+
+} // namespace nasal
--- /dev/null
+///@file Wrapper class for keeping Nasal objects save from the garbage collector
+//
+// Copyright (C) 2013 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_OBJECT_HOLDER_HXX_
+#define SG_NASAL_OBJECT_HOLDER_HXX_
+
+#include <simgear/nasal/naref.h>
+#include <simgear/structure/SGSharedPtr.hxx>
+
+namespace nasal
+{
+
+ /**
+ * Prevent a Nasal object from being destroyed by the garbage collector during
+ * the lifetime of this object.
+ */
+ class ObjectHolder:
+ public SGReferenced
+ {
+ public:
+
+ /**
+ *
+ */
+ ~ObjectHolder();
+
+ /**
+ * Get captured Nasal object
+ */
+ naRef get_naRef() const;
+
+ /**
+ * Save the given object as long as the returned holder exists.
+ *
+ * @param obj Object to save
+ */
+ static SGSharedPtr<ObjectHolder> makeShared(naRef obj);
+
+ protected:
+ naRef _ref;
+ int _gc_key;
+
+ /**
+ * @param obj Object to save
+ */
+ ObjectHolder(naRef obj);
+ };
+
+} // namespace nasal
+
+#endif /* SG_NASAL_OBJECT_HOLDER_HXX_ */
{
return nasal::to_nasal(c, d.getX());
}
-naRef f_freeFunction(nasal::CallContext) { return naNil(); }
+naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
int main(int argc, char* argv[])
{
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");
+ VERIFY( f );
+ VERIFY( f(3) == 3 );
+
+ boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
+ VERIFY( fs );
+ VERIFY( fs(14) == "14" );
+
+ typedef boost::function<void (int)> FuncVoidInt;
+ FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
+ VERIFY( fvi );
+ fvi(123);
+
+ typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
+ FuncMultiArg fma = hash.get<FuncMultiArg>("func");
+ VERIFY( fma );
+ VERIFY( fma("test", 3, .5) == "test" );
+
//----------------------------------------------------------------------------
// Test exposing classes to Nasal
//----------------------------------------------------------------------------
--- /dev/null
+#ifndef SG_FROM_NASAL_HELPER_HXX_
+# error Nasal cppbind - do not include this file!
+#endif
+
+#define n BOOST_PP_ITERATION()
+
+#ifndef SG_BOOST_FUNCTION_FROM_NASAL_FWD
+# define SG_CALL_TRAITS_PARAM(z, n, dummy)\
+ typename boost::call_traits<A##n>::param_type a##n
+# define SG_CALL_ARG(z, n, dummy)\
+ to_nasal(ctx, a##n)
+
+ template<
+ class Ret
+ BOOST_PP_COMMA_IF(n)
+ BOOST_PP_ENUM_PARAMS(n, class A)
+ >
+ typename boost::disable_if<boost::is_void<Ret>, Ret>::type
+ callNasalFunction( const ObjectHolder* holder
+ BOOST_PP_COMMA_IF(n)
+ BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0)
+ )
+ {
+ naContext ctx = naNewContext();
+ naRef args[] = {
+ BOOST_PP_ENUM(n, SG_CALL_ARG, 0)
+ };
+ const int num_args = sizeof(args)/sizeof(args[0]);
+
+ naRef result =
+ naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil());
+
+ Ret r = from_nasal_helper(ctx, result, static_cast<Ret*>(0));
+ naFreeContext(ctx);
+
+ return r;
+ }
+
+ template<
+ class Ret
+ BOOST_PP_COMMA_IF(n)
+ BOOST_PP_ENUM_PARAMS(n, class A)
+ >
+ typename boost::enable_if<boost::is_void<Ret>, Ret>::type
+ callNasalFunction( const ObjectHolder* holder
+ BOOST_PP_COMMA_IF(n)
+ BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0)
+ )
+ {
+ naContext ctx = naNewContext();
+ naRef args[] = {
+ BOOST_PP_ENUM(n, SG_CALL_ARG, 0)
+ };
+ const int num_args = sizeof(args)/sizeof(args[0]);
+
+ naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil());
+ naFreeContext(ctx);
+ }
+
+# undef SG_CALL_TRAITS_PARAM
+# undef SG_CALL_ARG
+#endif
+
+ template<
+ class Ret
+ BOOST_PP_COMMA_IF(n)
+ BOOST_PP_ENUM_PARAMS(n, class A)
+ >
+ boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
+ boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A)))
+#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD
+ ;
+#else
+ {
+ return boost::bind
+ (
+ &callNasalFunction<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, A)>,
+ ObjectHolder::makeShared(code)
+ BOOST_PP_COMMA_IF(n)
+ BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _)
+ );
+ }
+#endif
+
+#undef n
#include "nasal_traits.hxx"
#include <simgear/nasal/nasal.h>
+#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
+#include <simgear/nasal/cppbind/to_nasal.hxx>
#include <simgear/structure/exception.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
-#include <boost/utility/enable_if.hpp>
+#include <boost/bind.hpp>
+#include <boost/call_traits.hpp>
+#include <boost/function.hpp>
+#include <boost/preprocessor/iteration/iterate.hpp>
+#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/type_traits.hpp>
+#include <boost/utility/enable_if.hpp>
#include <string>
-#include <typeinfo> // std::bad_cast
#include <vector>
class SGPath;
*/
bool from_nasal_helper(naContext c, naRef ref, const bool*);
+ namespace detail
+ {
+#define SG_BOOST_FUNCTION_FROM_NASAL_FWD
+#define BOOST_PP_ITERATION_LIMITS (0, 9)
+#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
+#include BOOST_PP_ITERATE()
+#undef SG_BOOST_FUNCTION_FROM_NASAL_FWD
+ }
+
+ /**
+ * Convert a Nasal function to a boost::function with the given signature.
+ *
+ * @tparam Sig Signature of returned function (arguments and return value
+ * are automatically converted using from_nasal/to_nasal)
+ */
+ template<class Sig>
+ boost::function<Sig>
+ from_nasal_helper(naContext c, naRef ref, boost::function<Sig>*)
+ {
+ if( !naIsCode(ref)
+ && !naIsCCode(ref)
+ && !naIsFunc(ref) )
+ throw bad_nasal_cast("not a function");
+
+ return detail::boostFunctionFromNasal(ref, static_cast<Sig*>(0));
+ }
+
+ template<class Sig>
+ typename boost::enable_if< boost::is_function<Sig>,
+ boost::function<Sig>
+ >::type
+ from_nasal_helper(naContext c, naRef ref, Sig*)
+ {
+ return from_nasal_helper(c, ref, static_cast<boost::function<Sig>*>(0));
+ }
+
/**
* Convert a Nasal number to a C++ numeric type
*/
return Vec2(vec[0], vec[1]);
}
+ // Helpers for wrapping calls to Nasal functions into boost::function
+ namespace detail
+ {
+#define BOOST_PP_ITERATION_LIMITS (0, 9)
+#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
+#include BOOST_PP_ITERATE()
+ }
+
} // namespace nasal
#endif /* SG_FROM_NASAL_HELPER_HXX_ */