Binding Nested Structs in Chicken Scheme

I have a project right now in Chicken Scheme that has led me to need to create some bindings to a C library for the first time. It is every bit as challenging as I ever expected, but I'm making do, and making progress. One quandary that came up was how to write a binding for nested structs. I worked at the problem myself, searched the web to no avail, enlisted the help of friends, and finally asked in the Chicken IRC channel, and this is what I learned.

Here is a bit of C code similar to what I wanted to create a Chicken binding for. Notice that the first struct is a member of the second by value, not by pointer.

typedef struct {
    unsigned short red;
    unsigned short green;
    unsigned short blue;
    unsigned short alpha;
} RGBAColor;

typedef struct {
    char *name;
    RGBAColor color;
} RGBANameColor;

I'm using Chicken 4.6.0, with the help of the foreigners egg to write my bindings.

(import chicken scheme foreign foreigners)

Here are the two define-foreign-record-type forms to bind the nested structs. The part that had evaded me for so long was, in the form for RGBANameColor, the type of the nested struct. It is given as (struct RGBAColor). I had tried as many other combinations as I could think of, and almost resorted to writing scheme code to build up the structure as a blob, but this is the right way to nest a struct by value.

(define-foreign-record-type (rgbacolor RGBAColor)
  (constructor: make-rgbacolor)
  (destructor: free-rgbacolor)
  (unsigned-short red rgbacolor-red rgbacolor-red-set!)
  (unsigned-short green rgbacolor-green rgbacolor-green-set!)
  (unsigned-short blue rgbacolor-blue rgbacolor-blue-set!)
  (unsigned-short alpha rgbacolor-alpha rgbacolor-alpha-set!))

(define-foreign-record-type (rgbanamecolor RGBANameColor)
  (constructor: make-rgbanamecolor)
  (destructor: free-rgbanamecolor)
  (c-string name rgbanamecolor-name rgbanamecolor-name-set!)
  ((struct RGBAColor) color rgbanamecolor-color))

The next catch is that Chicken 4.6.0 does not support automatically creating a setter for the nested struct. If you need a setter for it, the workaround is to simply define it yourself:

(define rgbanamecolor-color-set!
  (foreign-lambda* void ((rgbanamecolor x) (rgbacolor c))
    "x->color = *c;"))

Now let's test it. Put all the code into a file, the C code at the top between #> and <# marks, and here is a snippet to do some basic manipulations of these objects:

(let ((nc (make-rgbanamecolor))
      (r (make-rgbacolor)))
  (rgbacolor-red-set! r 5)
  (rgbacolor-green-set! r 7)
  (rgbacolor-blue-set! r 11)
  (rgbacolor-alpha-set! r 100)
  (rgbanamecolor-name-set! nc "foo")
  (rgbanamecolor-color-set! nc r)
  (printf "~A: ~S ~S ~S ~S~%"
          (rgbanamecolor-name nc)
          (rgbacolor-red (rgbanamecolor-color nc))
          (rgbacolor-green (rgbanamecolor-color nc))
          (rgbacolor-blue (rgbanamecolor-color nc))
          (rgbacolor-alpha (rgbanamecolor-color nc))))

Here is the expected output of the program:

foo: 5 7 11 100

Big thanks to zbigniew on the Chicken IRC channel for helping me with this problem.