AdvancedDLSupport icon indicating copy to clipboard operation
AdvancedDLSupport copied to clipboard

Explain type matrix

Open ethindp opened this issue 3 years ago • 3 comments

From what I can tell, there isn't a description of how to map unions to .NET types. This is a problem for me since I have an API that uses unions and I'd like to bind it using this library. It would also be nice if there was something like a reference sheet that described both simple and complex types in C mapped to the associated simple and complex types in .NET. According to this SO question, the StructLayout attribute combined with the FieldOffset can simulate this with structs, but I don't know how well this would map across the FFI boundary. The library I'm binding has the following structs and associated union:

struct syz_AutomationPoint {
  int interpolation_type;
  double values[6];
  unsigned long long flags;
};

struct syz_AutomationAppendPropertyCommand {
  int property;
  struct syz_AutomationPoint point;
};

struct syz_AutomationClearPropertyCommand {
  int property;
};

struct syz_AutomationSendUserEventCommand {
  unsigned long long param;
};

union syz_AutomationCommandParams {
  struct syz_AutomationAppendPropertyCommand append_to_property;
  struct syz_AutomationClearPropertyCommand clear_property;
  struct syz_AutomationSendUserEventCommand send_user_event;
};

struct syz_AutomationCommand {
  syz_Handle target;
  double time;
  int type;
  unsigned int flags;
  union syz_AutomationCommandParams params;
};

SYZ_CAPI syz_ErrorCode syz_createAutomationBatch(syz_Handle *out, syz_Handle context, void *userdata,
                                                 syz_UserdataFreeCallback *userdata_free_callback);
SYZ_CAPI syz_ErrorCode syz_automationBatchAddCommands(syz_Handle batch, unsigned long long commands_len,
                                                      const struct syz_AutomationCommand *commands);
SYZ_CAPI syz_ErrorCode syz_automationBatchExecute(syz_Handle batch);

Therefore, one possible implementation of this translation might be:

using System.Runtime.InteropServices;

// ...
public struct AutomationPoint {
    public int InterpolationType;
    public double[6] Values;
    public ulong Flags;
}

public struct AutomationAppendPropertyCommand {
    public nint Property;
    public AutomationPoint Point;
}

public struct AutomationClearPropertyCommand {
    public int Property;
}

public struct AutomationSendUserEventCommand {
    public uint param;
}

[StructLayout(LayoutKind.Explicit, Pack=1)]
public struct AutomationCommandParams {
    [FieldOffset(0)]
    public AutomationAppendPropertyCommand AppendToProperty;
    [FieldOffset(56)]
    public AutomationClearPropertyCommand ClearProperty;
    // ...
}

The only major problem with this is that its majorly error-prone. I could use the sizeof operator but I'm not quite sure how I'd use that since FieldOffset requires a contiguous range. Is there a much better way of doing this?

ethindp avatar Aug 27 '22 20:08 ethindp

Using FieldOffset and an explicit struct layout is the way to go when dealing with unions, I'm afraid - this is one of those parts that gets hairy quick.

Nihlus avatar Aug 28 '22 19:08 Nihlus

@Nihlus Is there an easier way of computing the offsets, then? I really don't want to do [FieldOffset(sizeof(a) + sizeof(b) + sizeof(c) +...)]. That just looks really ugly.

ethindp avatar Aug 28 '22 19:08 ethindp

That's the only way I'm aware of, unfortunately. Interop code is ugly by its nature.

Nihlus avatar Aug 31 '22 15:08 Nihlus