The “anonymous struct and union types” pre-RFC doesn’t seem to be going anywhere, and we really badly need something to address the problem of C system headers defining structs whose documented fields are actually preprocessor macros referring to members of a nested union. I came up with an alternative idea in the shower this morning, please let me know what you think.
To motivate the problem, here is probably the simplest case found in real headers: struct sigaction
as defined by OSX sys/signal.h
.
/* union for signal handlers */
union __sigaction_u {
void (*__sa_handler)(int);
void (*__sa_sigaction)(int, struct __siginfo *,
void *);
};
/*
* Signal vector "template" used in sigaction call.
*/
struct sigaction {
union __sigaction_u __sigaction_u; /* signal handler */
sigset_t sa_mask; /* signal mask to apply */
int sa_flags; /* see signal options below */
};
/* if SA_SIGINFO is set, sa_sigaction is to be used instead of sa_handler. */
#define sa_handler __sigaction_u.__sa_handler
#define sa_sigaction __sigaction_u.__sa_sigaction
They get much messier than that; just look at siginfo_t
from the same header (but on FreeBSD or Linux, not OSX).
Right now, Rust can represent all of that except for the #define
s:
#[repr(C)] struct sigset_t { ... };
#[repr(C)] struct __siginfo { ... };
#[repr(C)]
union __sigaction_u {
__sa_handler: extern "C" fn(c_int) -> (),
__sa_sigaction: extern "C" fn(c_int, *mut __siginfo, *mut c_void),
};
#[repr(C)]
struct sigaction {
__sigaction_u: __sigaction_u,
sa_mask: sigset_t,
sa_flags: c_int,
};
My proposal, then, is to add a thing which expresses exactly what the #define
s express, only more hygenically. I call them “field aliases”. They look like this:
#[repr(C)]
pub struct sigaction {
__sigaction_u: __sigaction_u,
pub sa_mask: sigset_t,
pub sa_flags: c_int,
pub let sa_handler = __sigaction_u.__sa_handler,
pub let sa_sigaction = __sigaction_u.__sa_sigaction,
};
The abstract syntax is
(pub)? let NAME = ( FIELD '.' )* FIELD
as a new alternative production for struct
fields. NAME
is anything acceptable as a field name, and the chain of FIELD
s must refer to a (perhaps nested) existing field within the struct. Accessing NAME is exactly the same as accessing FIELD.FIELD.FIELD, except that the publicity of NAME is independent of the publicity of what it’s sugar for. (As shown above, the normal usage would be that the implementation-detail union and its fields are private, but the aliases are public.)
Why is this better than anonymous unions?
Because it is syntactic sugar, we don’t have to make any decisions about what anonymous unions mean, when you’re allowed to access which fields, etc.
Also, I suspect it will be easier to machine-generate from C headers.
Couldn’t we do this with macros?
Probably, but then you would have to write sa.sa_handler! = handler_fn
which is weird considering you don’t put an exclamation point on sa_mask
or sa_flags
. Also I don’t know if you can get the independent publicity effect with macros.
Can this be used in any kind of struct?
I don’t see why not, but I don’t know of any use for it other than the FFI scenario.