rubywrapper.h
1 #include <memory>
2 #include <string>
3 #ifdef _MSC_VER
4  #ifndef snprintf
5  #define snprintf _snprintf
6  #endif
7 #endif
8 
9 //! Wraps Ruby C interface and hides mysterious ruby.h from C++ libraries.
10 class Ruby {
11 private:
12  typedef std::pair<std::weak_ptr<void *>, std::weak_ptr<void *>> wrapped_t;
13 public:
14  Ruby(const char *scriptname);
15  ~Ruby();
16 
17  static const int Nil;
18  static const int False;
19  static const int True;
20 
21  //! \return state.
22  int evalProtect(const char* str);
23 
24  void printErrorInfo();
25 
26  typedef unsigned long Value; //has to be identical to VALUE
27 
28  void defineGlobalConst(const char *rbname, Value obj);
29 
30  //! C++ value to Ruby object
31  template <typename X>
32  static Value convertToRuby(X var);
33  static Value convertToRuby(const std::string &var);
34  //! Ruby object to C++ value
35  template <typename X>
36  static X convert(Value var);
37 
38  template <typename X>
39  static bool isConvertible(Value var);
40 
41  template <class P, class T>
42  struct Class {
43  Class(std::shared_ptr<P> parent, const char *rbname, Value super = Nil);
44  //!\todo MSVC2013 cl dies with multi-definitions.
45  template<Value(P::*Func)(const std::shared_ptr<T>&)>
46  void defineSingletonMethod(Value obj, const char *rbname);
47  template<Value(P::*Func)(const std::shared_ptr<T>&,Value)>
48  void defineSingletonMethod1(Value obj, const char *rbname);
49  template<Value(P::*Func)(const std::shared_ptr<T>&,Value,Value)>
50  void defineSingletonMethod2(Value obj, const char *rbname);
51  template<Value(P::*Func)(const std::shared_ptr<T>&)>
52  void defineMethod(const char *rbname);
53  template<Value(P::*Func)(const std::shared_ptr<T>&,Value)>
54  void defineMethod1(const char *rbname);
55  template<Value(P::*Func)(const std::shared_ptr<T>&,Value,Value)>
56  void defineMethod2(const char *rbname);
57  Value rubyClassObject() const;
58  Value rubyObject(const std::shared_ptr<T> &obj) const;
59  static std::weak_ptr<T> unwrap(Value v) {
60  return unwrap_internal<Ptr>(v).second;
61  }
62  private:
63 #ifdef _MSC_VER
64  #define RUBYDECL __cdecl
65 #else
66  #define RUBYDECL
67 #endif
68  typedef std::pair<std::weak_ptr<P>, std::weak_ptr<T>> Ptr;
69  static_assert(sizeof(Ptr) == sizeof(wrapped_t), "");
70  //! prepares a C-style function pointer to be called from Ruby.
71  //! \tparam Func a pointer to a C++ member function.
72  //! \return # of arguments in the ruby function.
73  template<Value(P::*Func)(const std::shared_ptr<T>&)>
74  int create_function(Value(**func)(Value)) {
75  *func = [](Value self)->Value {
76  char errstr[256];
77  try {
78  auto &st = unwrap_internal<Ptr>(self);
79  std::shared_ptr<P> p(st.first);
80  return (p.get()->*Func)(std::shared_ptr<T>(st.second));
81  }
82  catch(std::bad_weak_ptr &) {
83  snprintf(errstr, sizeof(errstr) - 1, "C object no longer exists.");}
84  catch(std::string &e) {
85  snprintf(errstr, sizeof(errstr) - 1, "%s", e.c_str());}
86  catch(const char *e) {
87  snprintf(errstr, sizeof(errstr) - 1, "%s", e);}
88  emit_error(errstr); return Nil;
89  };
90  return 0;
91  }
92  //! \todo use Arg... arg
93  template<Value(P::*Func)(const std::shared_ptr<T>&, Value)>
94  int create_function(Value(**func)(Value, Value)) {
95  *func = [](Value self, Value x)->Value {
96  char errstr[256];
97  try {
98  auto &st = unwrap_internal<Ptr>(self);
99  std::shared_ptr<P> p(st.first);
100  return (p.get()->*Func)(std::shared_ptr<T>(st.second), x);
101  }
102  catch(std::bad_weak_ptr &) {
103  snprintf(errstr, sizeof(errstr) - 1, "C object no longer exists.");}
104  catch(std::string &e) {
105  snprintf(errstr, sizeof(errstr) - 1, "%s", e.c_str());}
106  catch(const char *e) {
107  snprintf(errstr, sizeof(errstr) - 1, "%s", e);}
108  emit_error(errstr); return Nil;
109  };
110  return 1;
111  }
112  //! \todo use Arg... arg
113  template<Value(P::*Func)(const std::shared_ptr<T>&, Value, Value)>
114  int create_function(Value(**func)(Value, Value, Value)) {
115  *func = [](Value self, Value x, Value y)->Value {
116  char errstr[256];
117  try {
118  auto &st = unwrap_internal<Ptr>(self);
119  std::shared_ptr<P> p(st.first);
120  return (p.get()->*Func)(std::shared_ptr<T>(st.second), x, y);
121  }
122  catch(std::bad_weak_ptr &) {
123  snprintf(errstr, sizeof(errstr) - 1, "C object no longer exists.");}
124  catch(std::string &e) {
125  snprintf(errstr, sizeof(errstr) - 1, "%s", e.c_str());}
126  catch(const char *e) {
127  snprintf(errstr, sizeof(errstr) - 1, "%s", e);}
128  emit_error(errstr); return Nil;
129  };
130  return 2;
131  }
132  std::weak_ptr<P> m_parent;
133  Value m_rbObj;
134  };
135 private:
136  template <class Y>
137  static Y &unwrap_internal(Value self) {
138  return *static_cast<Y*>(unwrap_obj(self));
139  }
140  static Value wrap_obj(Value cl, void *p, void (*)(void *));
141  static void *unwrap_obj(Value self);
142 
143  static void define_method(Value cl, const char *rbname, Value (*func)(...), int argnum);
144  static void define_singleton_method(Value obj, const char *rbname, Value (*func)(...), int argnum);
145  static Value define_class(const char *rbname, Value super);
146 
147  //!C++ objects should be destroyed before.
148  static void emit_error(const char *errstr);
149 };
150 
151 template <class P, class T>
152 Ruby::Class<P,T>::Class(std::shared_ptr<P> parent, const char *rbname, Value super) : m_parent(parent) {
153  m_rbObj = define_class(rbname, super);
154 }
155 template <class P, class T>
156 template<Ruby::Value(P::*Func)(const std::shared_ptr<T>&)>
157 void
158 Ruby::Class<P,T>::defineMethod(const char *rbname) {
159  Value (*func)(Value);
160  typedef Value(*fp)(...);
161  int arg_num = create_function<Func>(&func);
162  define_method(m_rbObj, rbname, reinterpret_cast<fp>(func), arg_num);
163 }
164 template <class P, class T>
165 template<Ruby::Value(P::*Func)(const std::shared_ptr<T>&,Ruby::Value)>
166 void
167 Ruby::Class<P,T>::defineMethod1(const char *rbname) {
168  Value (*func)(Value,Value);
169  typedef Value(*fp)(...);
170  int arg_num = create_function<Func>(&func);
171  define_method(m_rbObj, rbname, reinterpret_cast<fp>(func), arg_num);
172 }
173 template <class P, class T>
174 template<Ruby::Value(P::*Func)(const std::shared_ptr<T>&,Ruby::Value,Ruby::Value)>
175 void
176 Ruby::Class<P,T>::defineMethod2(const char *rbname) {
177  Value (*func)(Value,Value,Value);
178  typedef Value(*fp)(...);
179  int arg_num = create_function<Func>(&func);
180  define_method(m_rbObj, rbname, reinterpret_cast<fp>(func), arg_num);
181 }
182 template <class P, class T>
183 template<Ruby::Value(P::*Func)(const std::shared_ptr<T>&)>
184 void
185 Ruby::Class<P,T>::defineSingletonMethod(Value obj, const char *rbname) {
186  Value (*func)(Value);
187  typedef Value(*fp)(...);
188  int arg_num = create_function<Func>(&func);
189  define_singleton_method(obj, rbname, reinterpret_cast<fp>(func), arg_num);
190 }
191 template <class P, class T>
192 template<Ruby::Value(P::*Func)(const std::shared_ptr<T>&,Ruby::Value)>
193 void
194 Ruby::Class<P,T>::defineSingletonMethod1(Value obj, const char *rbname) {
195  Value (*func)(Value,Value);
196  typedef Value(*fp)(...);
197  int arg_num = create_function<Func>(&func);
198  define_singleton_method(obj, rbname, reinterpret_cast<fp>(func), arg_num);
199 }
200 template <class P, class T>
201 template<Ruby::Value(P::*Func)(const std::shared_ptr<T>&,Ruby::Value,Ruby::Value)>
202 void
203 Ruby::Class<P,T>::defineSingletonMethod2(Value obj, const char *rbname) {
204  Value (*func)(Value,Value,Value);
205  typedef Value(*fp)(...);
206  int arg_num = create_function<Func>(&func);
207  define_singleton_method(obj, rbname, reinterpret_cast<fp>(func), arg_num);
208 }
209 template <class P, class T>
210 Ruby::Value
211 Ruby::Class<P,T>::rubyClassObject() const {return m_rbObj;}
212 template <class P, class T>
213 Ruby::Value
214 Ruby::Class<P,T>::rubyObject(const std::shared_ptr<T> &obj) const {
215  auto f = [](void *p){delete (Ptr*)p;};
216  return wrap_obj(m_rbObj, new Ptr(m_parent, obj), f);
217 }

Generated for KAME4 by  doxygen 1.8.3