SWIG: ruby proc->c function pointer

G

gga

Sorry for the slightly off-topic question. I am starting to use swig
to wrap some C++ library for ruby for the first time.
In the process of doing so, I realize I will need to pass proc objects
from ruby and turn them into function pointers in C, so as to provide a
callback mechanism.
I understand this can potentially be done with typemaps, but I am not
sure exactly how. I only need to have a single callback per class, so
I was thinking of storing the ruby callback within the class itself and
then have a common C wrap function that would map the C callback to the
appropiate ruby callbacks (ie. proc object) based on what was stored in
the class. I was also unsure if SWIG already provides some auxiliary
functions for doing something similar.
Does anyone have any pointers?
I'm already familiar with how ruby-fltk handles this, for example, and
I want to basically emulate something akin within the SWIG
meta-language. I'm looking at FXRuby but the code is a tad too complex
for a SWIG newbie.
 
K

Kouhei Sutou

Hi,

I'm writing bindings to Subversion by SWIG. This has some
callback codes.

In <[email protected]>
"SWIG: ruby proc->c function pointer" on Sat, 29 Jan 2005 03:25:52 +0900,
gga said:
In the process of doing so, I realize I will need to pass proc objects
from ruby and turn them into function pointers in C, so as to provide a
callback mechanism.

Here is an example:

--- callback.h
#ifndef CALLBACK_H
#define CALLBACK_H

typedef void (*callback_t) (void *user_data, const char *other_data);

void invoke(callback_t callback, void *user_data, const char *other_data);

#endif
---

--- callback.c
#include "callback.h"

void
invoke(callback_t callback, void *user_data, const char *other_data)
{
callback(user_data, other_data);
}
---

--- callback.i
%module callback

%{
void
wrap_callback(void *user_data, const char *other_data)
{
VALUE proc = (VALUE)user_data;
rb_funcall(proc, rb_intern("call"), 1, rb_str_new2(other_data));
}
%}

%typemap(in) (callback_t callback, void *user_data)
{
$1 = wrap_callback;
$2 = (void *)$input;
}

%include callback.h
%{
#include "callback.h"
%}
---

--- Makefile.swig
# -*- Makefile -*-

MODULE = callback
FEATURE = $(MODULE)
INTERFACE = $(MODULE).i

RUBY = ruby
SWIG = swig

SWIGOPT = -I/usr/local/include -I/usr/include -ruby -feature $(FEATURE)
WRAPPER = $(FEATURE)_wrap.c

swigall: $(WRAPPER) Makefile

$(WRAPPER): $(INTERFACE)
$(SWIG) $(SWIGOPT) -o $@ $(INTERFACE)

Makefile: extconf.rb
$(RUBY) extconf.rb
@if [ -f Makefile ] ; then\
echo "include Makefile.swig" >> Makefile;\
fi

swigclean:
@if [ -f Makefile ] ; then\
make -f Makefile clean;\
fi
rm -f Makefile $(WRAPPER)
---

--- extconf.rb
require 'mkmf'
create_makefile("callback")
---

--- to build
% make -f Makefile.swig
% make
---

--- sample usage
% irb -r callback
irb(main):001:0> Callback.invoke(Proc.new{|str| p str}, "abc")
"abc"
=> nil
 
G

gga

I finally got around to trying this. Thanks.
Unfortunately, the latest SWIG (v1.3.22) seems to choke on it, with:

irb(main):005:0> Callback.invoke(Proc.new{|str| p str}, "abc")
TypeError: cannot convert nil into String
from (irb):5:in `invoke'
from (irb):5

Looking at the code, SWIG fails in the StringValuePtr() conversion
here.

/* Get type mangle from class name */
SWIGRUNTIME(char *)
SWIG_Ruby_MangleStr(VALUE obj)
{
VALUE stype = rb_iv_get(obj, "__swigtype__");
return StringValuePtr(stype);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top