class CShadow::Attribute

This is the base class for all plug-in attribute classes used with the CShadow module. Each subclass provides information which CShadow uses to manage some of the housekeeping for the attribute:

(*) For Ruby versions before 1.7, requires a patch using the marshal.patch file (the patch is explained in marshal.txt).

The subclass hierarchy has two branches: ObjectAttribute and CNativeAttribute. The former is a reference to a Ruby object (in other words, a struct member of type VALUE. The latter has subclasses for various C data types, such as double and char *.

Object attributes

There are two kinds of object attributes. Both refer to Ruby objects and can be typed or untyped. The second is a slightly optimized variation that is restricted to references to other shadow objects.

class CShadow::ObjectAttribute

The syntax for adding an object attribute to a class is simple. The following code adds two object attributes, one untyped and one typed:

class A
  include CShadow
  shadow_attr_accessor :obj => Object, :sym => Symbol
end

(See cshadow.html for variations on shadow_attr_accessor.)

Assignment to obj performs no type checking. Assignment to sym raises a TypeError unless the object assigned is a Symbol or nil. Type checking always allows nil in addition to the specified type. In each case, the attribute is initialized to nil.

The referenced Ruby object is marked to protect it from the garbage collector.

class CShadow::ShadowObjectAttribute

ShadowObjectAttribute is a restricted variant of ObjectAttribute in which the object referred to must belong to a class that includes CShadow. The actual pointer is to the shadow struct itself, rather than a VALUE. This difference is transparent to Ruby code. The syntax for this variant differs only in the use of brackets around the type. For example, using the class A defined above:

class B
  include CShadow
  shadow_attr_accessor :a => [A]

  def initialize
    self.a = A.new
    a.sym = :something
  end
end

Note that a shadow struct always has a self pointer, so a ShadowObjectAttribute contains essentially the same information as an ObjectAttribute. It is included for situation in which the efficiency of a direct reference to the shadow struct is desirable. Note that only ObjectAttributes can refer to general Ruby objects which may or may not include the CShadow module.

The accessors work just as with ObjectAttribute, with type checking performed by the writer. From Ruby, these two kinds of attributes are indistinguishable in all respects except their declaration syntax.

The referenced Ruby object is marked to protect it from the garbage collector.

C native attributes

CNativeAttribute and its subclasses handle all but the two special cases described above. The general form for declarations of such attributes is:

shadow_attr_accessor ruby_var => c_declaration

where ruby_var is the name (symbol or string) which will access the data from Ruby, and c_declaration is the string used to declare the data. For example:

shadow_attr_accessor :x => "double x", :y => "int yyy"

Note that the symbol and C identifier need not be the same.

Native attributes fall into two categories: those that embed data within the struct, and those that point to a separately allocated block. Embedded attributes are limited in that they are of fixed size. Pointer attributes do not have this limitation. But programmers should be wary of treating them as separate objects: the lifespan of the referenced data block is the same as the lifespan of the Ruby object. If the Ruby object and its shadow are garbage collected while the data is in use, the data will be freed and no longer valid.

When using a separately allocated data block, it is a good practice is to use "copy" semantics, so that there can be no other references to the data. See CharPointerAttribute, for example. Reading or writing to such an attribute has copy semantics, in the following sense. On assignment, the Ruby string argument is copied into an allocated block; later references to this attribute generate a new Ruby string which is a copy of that array of char.

Some CNativeAttribute classes are included for int, long, double, double *, char *, etc.

Uninitialized numeric members are 0. Accessors for unitialized strings return nil.

Adding new attribute classes

Each attribute class must define a class method called 'match' which returns true if the right hand side of the ':name => ...' expression is recognized as defining an attribute of the class. The class should have an initialize method to supply custom code for readers, writers, type checking, memory management, and serialization. (If serialization methods are omitted, the attribute will be ignored during dump/load.) The easiest way is to follow the examples. For many purposes, most of the work can be done by subclassing existing classes.

The dump and load methods require a bit of explanation. Each attribute provides code to dump and load itself in a very generic way. The dump code must operate on a ruby array called result. It must push _one_ piece of ruby data (which may itself be an array, hash, etc.) onto this array. Similarly, the load code operates on a ruby array called from_array. It must shift _one_ piece of ruby data from this array. (Probably it would have been more efficient to use LIFO rather than FIFO. Oh, well.)

To do:

Limitations: