xavierleroy / camlidl

Stub code generator for OCaml/C interface
Other
34 stars 8 forks source link

Union cases not included in generated C header #4

Open pvaibhav opened 6 years ago

pvaibhav commented 6 years ago

Setup

In my upload.idl I have this:

union progress switch(int type) {
  case Starting:;
  case Uploading: double progressPercent;
  case Finished:;
  case Error:;
};

Running camlidl -header upload.idl generates this in the .mli (looks fine though I'd prefer avoiding "union_2" alias):

type union_2 =
  | Starting
  | Uploading of float
  | Finished
  | Error
and progress = union_2

HOWEVER the following definition is generated in the C header (no mention of case labels):

struct progress {
  int type; // <------------ ???
  union {
    double progressPercent;
  } u;
};

Problem

The definition for the various cases of the discriminant are not included in the header and are effectively lost on the C side. The upload_stubs.c file still makes use of the case labels as if they were defined like an enum:

value camlidl_c2ml_upload_struct_progress(struct progress * _c1, camlidl_ctx _ctx)
{
  value _v2;
  value _v3;
  switch ((*_c1).type) {
  case Starting: // <--------------- undefined!
    _v2 = Val_int(0);
    break;
  case Uploading: // <------------- undefined!
    _v3 = copy_double((*_c1).u.progressPercent);
...
...
...

This would cause the stubs to fail to compile, and users of the header to not have any idea what values are supported for the discriminant field.

Solution attempts

I tried separately defining the union's cases as a separate enum progress_type { Starting, ... in the idl file, then using [switch_is(type)] union progress { .. } inside en enclosing struct with a field enum progress_type type;. But this causes the generated .mli file to duplicate the definitions first as a Ocaml enumerated type, then again as a sum type. So the C stubs are now complete but the .mli has compile errors.

Question ..

How to actually use unions?

Ideal solution

The generated header should include an enum of the case labels like so:

struct progress {
  enum {
    Starting,
    Uploading,
    Finished,
    Error
  } type;
  union {
    double progressPercent;
  } u;
};

Or perhaps an enum progress_type { ... } outside the struct.