[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

C library extension question

Oliver

7/16/2007 7:19:00 PM

hi, folks -

I am working on a ruby extension for a C library, and having
difficulty of figuring out how to deal with this structure and
wrapping it nicely in Ruby. it is a command dispatch structure, where
you supply an array of function pointers:

/* command dispatch structure */
typedef int (*proxy_cmd)(int trans_id, int nargs, char **args);

struct proxy_commands {
int cmd_base;
int cmd_size;
proxy_cmd * cmd_funcs;
};
typedef struct proxy_commands proxy_commands;

/* end of definition */

Then, as a user you can define an array of function pointers like
this:

proxy_cmd cmds[] = {
func_a,
func_b,
func_c,
...
};

and fill in the structure:

proxy_commands mytabs = {
CMD_BASE;
sizeof(cmds)/sizeof(proxy_cmd),
cmds
}

An example of API will look like this:
register(&mytabs, .... )

What is the best way of wrapping this in Ruby?

>From end user perspective, I am thinking the interaction like this:

def func_a ( ...)
end

def func_b( ...)
end

mytabs = [func_a, func_b]
register(mytabs)

If you have experience on writing C extensions, I'd appreciate your
input.
TIA

Oliver

8 Answers

Ryan Davis

7/16/2007 10:53:00 PM

0


On Jul 16, 2007, at 12:20 , Oliver wrote:

> /* command dispatch structure */
> typedef int (*proxy_cmd)(int trans_id, int nargs, char **args);
>
> struct proxy_commands {
> int cmd_base;
> int cmd_size;
> proxy_cmd * cmd_funcs;
> };
> typedef struct proxy_commands proxy_commands;

What you're looking for is probably Data_Wrap_Struct and friends. See
ruby.h and intern.h. For a simple example of this in action, look at
the image_science.rb code (available via gems or on the seattlerb
project on rubyforge). It is only 228 lines long currently so it is a
pretty easy read.

> Then, as a user you can define an array of function pointers like
> this:
>
> proxy_cmd cmds[] = {
> func_a,
> func_b,
> func_c,
> ...
> };
>
> and fill in the structure:
>
> proxy_commands mytabs = {
> CMD_BASE;
> sizeof(cmds)/sizeof(proxy_cmd),
> cmds
> }

I'd suggest using a ruby array at this stage. Cleaner.

> An example of API will look like this:
> register(&mytabs, .... )
>
> What is the best way of wrapping this in Ruby?

Well, the BEST way is to not wrap it at all:

def func_a; ...; end
def func_b; ...; end

msgs = [:func_a, :func_b]

msgs.each do |msg|
send msg
end


Short of that, you'll want to poke around with DataWrapStruct.

Oliver

7/16/2007 11:50:00 PM

0

Thanks for the suggestion, I will take a look at the sample lib you
suggested.
However, I don't fully understand the reasoning of "not wrapping it".

Here is my line of thinking:

- the original C function register() expects an array of function
pointers, and those functions are suppose to be user-supplied and
implemented by C.

- Ideally, we should now allow those functions to be implemented by
ruby ... is this possible at all?

thanks

Oliver


On Jul 16, 6:53 pm, Ryan Davis <ryand-r...@zenspider.com> wrote:
> On Jul 16, 2007, at 12:20 , Oliver wrote:
>
> > /* command dispatch structure */
> > typedef int (*proxy_cmd)(int trans_id, int nargs, char **args);
>
> > struct proxy_commands {
> > int cmd_base;
> > int cmd_size;
> > proxy_cmd * cmd_funcs;
> > };
> > typedef struct proxy_commands proxy_commands;
>
> What you're looking for is probably Data_Wrap_Struct and friends. See
> ruby.h and intern.h. For a simple example of this in action, look at
> the image_science.rb code (available via gems or on the seattlerb
> project on rubyforge). It is only 228 lines long currently so it is a
> pretty easy read.
>
>
>
> > Then, as a user you can define an array of function pointers like
> > this:
>
> > proxy_cmd cmds[] = {
> > func_a,
> > func_b,
> > func_c,
> > ...
> > };
>
> > and fill in the structure:
>
> > proxy_commands mytabs = {
> > CMD_BASE;
> > sizeof(cmds)/sizeof(proxy_cmd),
> > cmds
> > }
>
> I'd suggest using a ruby array at this stage. Cleaner.
>
> > An example of API will look like this:
> > register(&mytabs, .... )
>
> > What is the best way of wrapping this in Ruby?
>
> Well, the BEST way is to not wrap it at all:
>
> def func_a; ...; end
> def func_b; ...; end
>
> msgs = [:func_a, :func_b]
>
> msgs.each do |msg|
> send msg
> end
>
> Short of that, you'll want to poke around with DataWrapStruct.


Ryan Davis

7/17/2007

0


On Jul 16, 2007, at 16:50 , Oliver wrote:

> Thanks for the suggestion, I will take a look at the sample lib you
> suggested.
> However, I don't fully understand the reasoning of "not wrapping it".

I was just suggesting that thinking laterally might be an
alternative. Obviously not if you're using a specific 3rd party
library that you need to use. But if you just want an event engine,
we're talking a TEENY amount of code in ruby (sans-leaks, sans-cores,
sans-icky) compared to C.

> Here is my line of thinking:
>
> - the original C function register() expects an array of function
> pointers, and those functions are suppose to be user-supplied and
> implemented by C.

what users at what level/language?

> - Ideally, we should now allow those functions to be implemented by
> ruby ... is this possible at all?

I think you'd have to do some extra work to wrap up rb_funcall itself.


Oliver

7/17/2007 1:34:00 AM

0

probably I didn't make myself clear:

Under normal usage, the library expects user to supply some functions
in C, such as func_a(), func_b(), through function pointers defined in
above dispatch command structure.

Now, from a wrapper stand point of view, I was hoping that the user-
provided function func_a(), func_b() etc. can be done by ruby as well
- it will be very awkward for a user to use partial c, partial ruby
for the same library. I don't see why rb_funcall() can help in this
case - in a sense, this case calls for a way to map ruby function into
C function, for the sake of using the C library call.

thanks

Oliver



On Jul 16, 8:00 pm, Ryan Davis <ryand-r...@zenspider.com> wrote:
> On Jul 16, 2007, at 16:50 , Oliver wrote:
>
> > Thanks for the suggestion, I will take a look at the sample lib you
> > suggested.
> > However, I don't fully understand the reasoning of "not wrapping it".
>
> I was just suggesting that thinking laterally might be an
> alternative. Obviously not if you're using a specific 3rd party
> library that you need to use. But if you just want an event engine,
> we're talking a TEENY amount of code in ruby (sans-leaks, sans-cores,
> sans-icky) compared to C.
>
> > Here is my line of thinking:
>
> > - the original C function register() expects an array of function
> > pointers, and those functions are suppose to be user-supplied and
> > implemented by C.
>
> what users at what level/language?
>
> > - Ideally, we should now allow those functions to be implemented by
> > ruby ... is this possible at all?
>
> I think you'd have to do some extra work to wrap up rb_funcall itself.


Ryan Davis

7/17/2007 2:29:00 AM

0


On Jul 16, 2007, at 18:35 , Oliver wrote:

> probably I didn't make myself clear:
>
> Under normal usage, the library expects user to supply some functions
> in C, such as func_a(), func_b(), through function pointers defined in
> above dispatch command structure.
>
> Now, from a wrapper stand point of view, I was hoping that the user-
> provided function func_a(), func_b() etc. can be done by ruby as well
> - it will be very awkward for a user to use partial c, partial ruby
> for the same library. I don't see why rb_funcall() can help in this
> case - in a sense, this case calls for a way to map ruby function into
> C function, for the sake of using the C library call.

I suggested rb_funcall because it is the C entry point into a ruby
method. Since the function pointer signature doesn't match up with
ruby's, I don't think you can share between C and ruby 1:1. But, you
might be able to wrap it up in such a way that you can call through
from C into ruby.

I wasn't suggesting the user work in a mix of the two, just you.

Really NonFunctional Basic Visual:

def func_a
puts "yay!"
end

Workhorse.register :func_a

----

void rb_func_wrapper() {
rb_funcall(rb_cKernel, ID2SYM(...));
}

void rb_register(VALUE sym_name) {
register(rb_func_wrapper << N & SYM2ID(sym_name)); // or something
equally scary
}

----

not that I think you can do that... but it is a thought.

----

Another thought, assuming you have the latitude, is to dynamically
generate the C functions for register using something like RubyInline.



Ryan Davis

7/17/2007 2:29:00 AM

0


On Jul 16, 2007, at 19:00 , Francis Cianfrocca wrote:

> On 7/16/07, Oliver <fwang2@gmail.com> wrote:
>>
>> probably I didn't make myself clear:
>>
>> Under normal usage, the library expects user to supply some functions
>> in C, such as func_a(), func_b(), through function pointers
>> defined in
>> above dispatch command structure.
>>
>> Now, from a wrapper stand point of view, I was hoping that the user-
>> provided function func_a(), func_b() etc. can be done by ruby as well
>> - it will be very awkward for a user to use partial c, partial ruby
>> for the same library. I don't see why rb_funcall() can help in this
>> case - in a sense, this case calls for a way to map ruby function
>> into
>> C function, for the sake of using the C library call.
>
> Write func_a, func_b, func_c as C functions that massage their
> arguments
> into Rubyland and call rb_funcall to hit the user-written Ruby
> functions.
> Similarly massage the return values from Ruby back into C values.

Except that he wants the users to write func_[a-c] in ruby, to be
invoked by C, via c function pointers. It is that last teeny
requirement that I think blows this up.


George

7/17/2007 3:00:00 AM

0

On 7/17/07, Oliver <fwang2@gmail.com> wrote:
>
> Now, from a wrapper stand point of view, I was hoping that the user-
> provided function func_a(), func_b() etc. can be done by ruby as well
> - it will be very awkward for a user to use partial c, partial ruby
> for the same library. I don't see why rb_funcall() can help in this
> case - in a sense, this case calls for a way to map ruby function into
> C function, for the sake of using the C library call.

Hi Oliver,

Does the library let you specify an argument to pass to these
callbacks when you register them somehow? If so, I'd probably define
the callbacks as Procs (or anything with #call) on the ruby side, and
in the C side, register the same function, say run_command(VALUE proc)
for all the commands, passing the Proc as an argument. run_command()
would just use rb_funcall to call the proc's #call.

If not, and you do indeed have to register distinct C functions for
each command, two ideas come to mind:

1. Have a hard limit on the number of commands, and define C functions
func1, func2, ... funcN to call the n-th one.
2. Use RubyInline to dynamically define each C function, load it as a
shared library, and add it to your struct (as Ryan just mentioned).

As for the interface on the ruby side, a few options come to mind.
The more direct translation of the C API:

command1 = lambda{|*args| ... }
command2 = lambda{|*args| ... }
...
register(command1, command2, ...)

(You could have #register have symbols denote method calls on Object
too, but I think procs would feel the most natural.)

Define by blocks on a method:

add_command{|*args| ... }
add_command{|*args| ... }
...
register_commands

Register by block:

register_commands do |c|
c.add{|*args| ... }
c.add{|*args| ... }
end

Hope this gives you some ideas,
George.

Oliver

7/17/2007 6:12:00 PM

0

Thanks for the suggestions, Ryan and George.
I will explore along those lines.

Oliver

On Jul 16, 10:59 pm, George <george.og...@gmail.com> wrote:
> On 7/17/07, Oliver <fwa...@gmail.com> wrote:
>
>
>
> > Now, from a wrapper stand point of view, I was hoping that the user-
> > provided function func_a(), func_b() etc. can be done by ruby as well
> > - it will be very awkward for a user to use partial c, partial ruby
> > for the same library. I don't see why rb_funcall() can help in this
> > case - in a sense, this case calls for a way to map ruby function into
> > C function, for the sake of using the C library call.
>
> Hi Oliver,
>
> Does the library let you specify an argument to pass to these
> callbacks when you register them somehow? If so, I'd probably define
> the callbacks as Procs (or anything with #call) on the ruby side, and
> in the C side, register the same function, say run_command(VALUE proc)
> for all the commands, passing the Proc as an argument. run_command()
> would just use rb_funcall to call the proc's #call.
>
> If not, and you do indeed have to register distinct C functions for
> each command, two ideas come to mind:
>
> 1. Have a hard limit on the number of commands, and define C functions
> func1, func2, ... funcN to call the n-th one.
> 2. Use RubyInline to dynamically define each C function, load it as a
> shared library, and add it to your struct (as Ryan just mentioned).
>
> As for the interface on the ruby side, a few options come to mind.
> The more direct translation of the C API:
>
> command1 = lambda{|*args| ... }
> command2 = lambda{|*args| ... }
> ...
> register(command1, command2, ...)
>
> (You could have #register have symbols denote method calls on Object
> too, but I think procs would feel the most natural.)
>
> Define by blocks on a method:
>
> add_command{|*args| ... }
> add_command{|*args| ... }
> ...
> register_commands
>
> Register by block:
>
> register_commands do |c|
> c.add{|*args| ... }
> c.add{|*args| ... }
> end
>
> Hope this gives you some ideas,
> George.