cisco / ChezScheme

Chez Scheme
Apache License 2.0
6.99k stars 987 forks source link

Possible bug with foreign-procedure and struct arguments #870

Closed deepankarsharma closed 2 months ago

deepankarsharma commented 2 months ago

I am wrapping this C api


// Color, 4 components, R8G8B8A8 (32bit)
typedef struct Color {
    unsigned char r;        // Color red value
    unsigned char g;        // Color green value
    unsigned char b;        // Color blue value
    unsigned char a;        // Color alpha value
} Color;

Color Fade(Color color, float alpha);

in the following way

  (define-ftype Color
    (struct
      [r unsigned-8]
      [g unsigned-8]
      [b unsigned-8]
      [a unsigned-8]))

  (define fade
    (foreign-procedure "Fade" ((& Color) float) (& Color)))

Based on my reading of (& ) can be used to send and receive structs by value.

However when trying to use the above code I get an arity-error. For some reason Chez thinks that this is a function that takes three arguments.

> (define fp (foreign-procedure "Fade" ((& Color) float) (& Color)))
> (define c (make-color 4 4 4 4))
> (fp c 44.)
Exception: incorrect number of arguments 2 to #<procedure fp>
debug>         
> (fp c c 44.)
> 

Calling it with three arguments appears to not throw any errors.

mflatt commented 2 months ago

When a C-level result is a struct, then the procedure created by foreign-procedure needs a pointer to copy the result struct into. The pointer is provided to fp as an extra argument before all of the others. This is described in the documentation at the second (& ftype-name):, which is in the part about result types.

So, the intended calling pattern is like this:

> (define c (make-color 4 4 4 4))
> (define result (make-color 0 0 0 0))
> (fp result c 44.) ; `result` content is modified to be the return value
deepankarsharma commented 2 months ago

Thank you for the clarification!

deepankarsharma commented 2 months ago

Closing since this was not a bug but an oversight on my part.