From: Joel VanderWerf Date: 2009-06-16T02:30:29+09:00 Subject: Re: wrapping a C struct[] constant Martin DeMello wrote: > another basic thing I missed is the > ability to define a typemap and then have a ruby class > serialised/deserialised to a C struct. (Is that what Cgenerator's > CShadow is all about?). Are these not common use cases? Would this be like swig in reverse? Input a ruby class with type annotations, output C header, accessors, etc? I'd like to do that for the special case of BitStruct classes (fixed-length, packed fields, usually numeric or character, stored in a ruby String using pack/unpack), so that once you define a network protocol or other binary format in ruby, you can share your code with C programmers (and via swig with other languages). That seems feasible, and I did actually do this with a predecessor of BitStruct, using cgen. But how would you handle a more general case, like a class with a hash or array attribute? CShadow is similar, but instead of inheriting from String like BitStruct, its instances are T_DATA (ruby objects with a blob that can only be accessed from C). Unlike a BitStruct, this blob is not intended for sending outside of the ruby+C world. For example, a "self" pointer is automatically added at the beginning of the blob. Including CShadow in your class lets you define the structure of the T_DATA object in ruby, in terms of accessors of various types. When your code runs, it uses cgenerator to build an extension that takes care of all the boiler plate functions: mark, free, accessors with type checking/conversion, alloc, init, inspect, marshal, and yaml. Plus it handles inheritance and sets up introspection methods. [See example below.] CShadow also gives you tools to distribute source code in separate .c and .h files, so that when you make a minor change in the definitions embedded in ruby, you minimize how much needs to be recompiled. This works well enough that even if the generated code is a few Mb, you can let cgenerator do its full generate/make cycle every time you run your program, without noticing much delay. You can add C functions to a CShadow class inline in ruby source just as with cgenerator. But CShadow only supports a few kinds of attributes "out of the box": ruby object references, native scalar data of various sizes, and native pointers to char, double, array of double, etc. You can add new attr types with a little work, but it's far from automatic. These are just two special case solutions. I'm not seeing what a general solution would look like. What kinds of classes/attributes are there in your use cases? -------------------------------- require 'cgen/cshadow' class Parent include CShadow shadow_attr_accessor :ruby_str => String # type-checked VALUE type shadow_attr_accessor :c_int => "int c_int" end class Child < Parent shadow_attr_accessor :c_str => "char *c_str" shadow_attr_accessor :obj => Object # VALUE type end Parent.commit # we're done adding attrs and methods, so make. x = Child.new x.ruby_str = "foo" x.c_str = "bar" x.obj = [1,2,3] x.c_int = 3 p x CShadow.allow_yaml y x __END__ Output: # --- !path.berkeley.edu,2006/cshadow:Child ruby_str: foo c_int: 3 c_str: bar obj: - 1 - 2 - 3 -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407