[plt-scheme] define-cstruct, mutual dependency
Robert Nikander wrote:
> Hi,
>
> I'm trying to work with two C structs that use each other in their
> definitions. I don't see a way to define this with `define-cstruct'.
>
> struct Object {
> Class *isa;
> }
> struct Class : Object {
> const char *name;
> ...
> }
>
> This doesn't work, because I can't mention one before the other:
>
> (define-cstruct _Object ([isa _Class-pointer]))
> (define-cstruct (_Class _Object) ([name _string] ...)
>
> I'd like to declare the inheritance relation so I can pass classes to
> functions that expect objects.
>
> Any ideas?
After a lot of futzing around I got this to work
(require (lib "foreign.ss"))(unsafe!)
(define-cstruct _A
((x _int)
(b (_cpointer #f #f (lambda (c) c)
(lambda (c) (cpointer-push-tag! c B-tag) c)))))
(define-cstruct (_B _A)
((q _int)))
(define lib (ffi-lib "libx"))
(define get (get-ffi-obj "getB" lib (_fun -> _B-pointer)))
(let ((b (get)))
(printf "~a\n" b)
(printf "~a\n" (B-q b))
(printf "~a\n" (A-b b))
; (cpointer-push-tag! (A-b b) B-tag)
; (set-cpointer-tag! (A-b b) B-tag)
(printf "a-tag ~a\n" (cpointer-has-tag? (A-b b) A-tag))
(printf "b-tag ~a\n" (cpointer-has-tag? (A-b b) B-tag))
(printf "~a\n" (A-b b))
(printf "eq? ~a\n" (eq? b (A-b b)))
(printf "~a\n" (B-q (A-b b)))
)
Where the magic is in (lambda (c) (cpointer-push-tag! c B-tag) c), which
forces the foreign library to treat the returned object as a B type. I
initially tried this
(define-cstruct _A ((x _int) (b (_cpointer #f)))
and then rely on (cpointer-push-tag! (A-b b) B-tag) to set the type, I
have that line commented out above. I'm not entirely sure why that
didn't work.
Also for whatever reason (eq? b (A-b b)) was #f even though the C code did
struct B * b;
b->a.b = b;
but you probably don't need that anyway.