Feature-discriminate struct fields

I've been toying around with the cfg annotation, but it seems lackluster from what I've seen. From what I've seen, it has to be prepended to every struct/const/static var/etc that follows that you want the cfg to apply to? It seems rather....not ideal unless there's a way to group them all under one annotation (ie. curly braces, maybe, but that would imply scope as well) I know for statements in code blocks, a simple if cfg!(feature = "foo") { ... } suffices but not sure if there's an annotation equivalent.

If I'm not clear, I'm trying to accomplish in Rust what the following in C/C++ might do:

struct Person {
    char *name;
    int age;
#ifdef MORE_INFO_SUPPORTED
    char* job_title;
#endif
};

You want cfg-if! It provides a macro which does at least some of what you want it to.

cfg_if!{ if #[cfg( feature = "Foo" )]{
    /* Conditionally compiled code goes here */
} else if #[cfg( feature = "Bar")]  {
   /* ... */
}}

The only real downside to the crate in my opinion is that it will nest things twice whenever you want to do conditional compilation and most IDEs will auto-indent accordingly. Personally I use a mix of it for large blocks of code and single line #[cfg] directives for things like single imports.
Another option is to put all your conditional compilation into its own module. Something like:

#[cfg( feature = "Foo" )]
mod foo {
    /* Conditionally compiled code goes here */
}

but that only works if your feature is gating a whole bunch of conditional compilation and get frustrated by the extra indentation, think something like platform specific utilities or a compatibility layer into another crate.

struct Person {
    name: String
    age: u32,
    #[cfg(feature = "more-info-supported")]
    job_title: String,
}
5 Likes

I'd have to do that for every field with that feature, huh? Darn...

To be clear, the cfg_if!{} macro can be used in any place a macro can be used, that includes struct definitions.

struct Person {
    name: String,
    age: u32,
    cfg_if!{ if #[cfg( feature = "more-info" )] {
        clearance_level: u8,
        job_title: String,
    }}
}

EDIT: I'm completely wrong about this, it worked for me earlier in a trait which is a different beast entirely and doesn't really help you.

Maybe try wrapping the conditional values up in their own structure, an enum or tuple. Depending on how involved the optional values are having a struct wrapping them might make them easier to work with

Hmmm? No, macros can only expand to items, statement lists, expressions, patterns, or types. Your example fails in the playground:

error: expected `:`, found `!`
 --> src/main.rs:6:11
  |
6 |     cfg_if!{ if #[cfg( feature = "more-info" )] {
  |           ^ expected `:`

error: aborting due to previous error

So in declaring a bitflags flag struct for a crate I'm making that implements the Hotline protocol, one such flag struct describes user privilege flags. The way Hotline does it is very weird: depending on endian, the bits of each byte are reversed, but the bytes themselves are not swapped. I used #[cfg(target_endian "...")] ("..." of course being "big" and "little"), but I'm not sure if I was supposed to document it twice?

bitflags! {
	/// There are 3 types of access privileges: general, folder and bundle.
	/// Folder privileges are set per folder. Bundle access is related to the logical grouping
	/// of the information. General access privileges are used to set privileges for a user.
	#[cfg(target_endian = "big")]
	pub struct UserAccess: u64 {
		const DELETE_FILE = 1;
		const UPLOAD_FILE = 2;
		const DOWNLOAD_FILE = 4;
		const RENAME_FILE = 8;
		const MOVE_FILE = 16;
		const CREATE_FOLDER = 32;
		const DELETE_FOLDER = 64;
		const RENAME_FOLDER = 128;
		const MOVE_FOLDER = 256;
		const READ_CHAT = 512;
		const SEND_CHAT = 1024;
		const CREATE_CHAT = 2048;
		const CLOSE_CHAT = 4096;
		const SHOW_IN_LIST = 8192;
		const CREATE_USER = 16384;
		const DELETE_USER = 32768;
		const OPEN_USER = 65536;
		const MODIFY_USER = 131072;
		const CHANGE_OWN_PASS = 262144;
		const SEND_PRIV_MSG = 524288;
		const NEWS_READ_ART = 1048576;
		const NEWS_POST_ART = 2097152;
		const DISCON_USER = 4194304;
		const CANNOT_BE_DISCON = 8388608;
		const GET_CLIENT_INFO = 16777216;
		const UPLOAD_ANYWHERE = 33554432;
		const ANY_NAME = 67108864;
		const NO_AGREEMENT = 134217728;
		const SET_FILE_COMMENT = 268435456;
		const SET_FOLDER_COMMENT = 536870912;
		const VIEW_DROP_BOXES = 1073741824;
		const MAKE_ALIAS = 2147483648;
		const BROADCAST = 4294967296;
		const NEWS_DELETE_ART = 8589934592;
		const NEWS_CREATE_CAT = 17179869184;
		const NEWS_DELETE_CAT = 34359738368;
		const NEWS_CREATE_FLDR = 68719476736;
		const NEWS_DELETE_FLDR = 137438953472;
		const UPLOAD_FOLDER = 274877906944;
		const DOWNLOAD_FOLDER = 549755813888;
		const SEND_MESSAGE = 1099511627776;
		const FAKE_RED = 2199023255552;
		const AWAY = 4398046511104;
		const CHANGE_NICK = 8796093022208;
		const CHANGE_ICON = 17592186044416;
		const SPEAK_BEFORE = 35184372088832;
		const REFUSE_CHAT = 70368744177664;
		const BLOCK_DOWNLOAD = 140737488355328;
		const VISIBLE = 281474976710656;
		const CAN_VIEW_INVISIBLE = 562949953421312;
		const CAN_FLOOD = 1125899906842624;
		const VIEW_OWN_DROP_BOX = 2251799813685248;
		const DONT_QUEUE = 4503599627370496;
		const ADM_IN_SPECTOR = 9007199254740992;
		const POST_BEFORE = 18014398509481984;
	}

	/// There are 3 types of access privileges: general, folder and bundle.
	/// Folder privileges are set per folder. Bundle access is related to the logical grouping
	/// of the information. General access privileges are used to set privileges for a user.
	#[cfg(target_endian = "little")]
	pub struct UserAccess: u64 {
		const RENAME_FOLDER = 1;
		const DELETE_FOLDER = 2;
		const CREATE_FOLDER = 4;
		const MOVE_FILE = 8;
		const RENAME_FILE = 16;
		const DOWNLOAD_FILE = 32;
		const UPLOAD_FILE = 64;
		const DELETE_FILE = 128;
		const DELETE_USER = 256;
		const CREATE_USER = 512;
		const SHOW_IN_LIST = 1024;
		const CLOSE_CHAT = 2048;
		const CREATE_CHAT = 4096;
		const SEND_CHAT = 8192;
		const READ_CHAT = 16384;
		const MOVE_FOLDER = 32768;
		const CANNOT_BE_DISCON = 65536;
		const DISCON_USER = 131072;
		const NEWS_POST_ART = 262144;
		const NEWS_READ_ART = 524288;
		const SEND_PRIV_MSG = 1048576;
		const CHANGE_OWN_PASS = 2097152;
		const MODIFY_USER = 4194304;
		const OPEN_USER = 8388608;
		const MAKE_ALIAS = 16777216;
		const VIEW_DROP_BOXES = 33554432;
		const SET_FOLDER_COMMENT = 67108864;
		const SET_FILE_COMMENT = 134217728;
		const NO_AGREEMENT = 268435456;
		const ANY_NAME = 536870912;
		const UPLOAD_ANYWHERE = 1073741824;
		const GET_CLIENT_INFO = 2147483648;
		const DOWNLOAD_FOLDER = 4294967296;
		const UPLOAD_FOLDER = 8589934592;
		const NEWS_DELETE_FLDR = 17179869184;
		const NEWS_CREATE_FLDR = 34359738368;
		const NEWS_DELETE_CAT = 68719476736;
		const NEWS_CREATE_CAT = 137438953472;
		const NEWS_DELETE_ART = 274877906944;
		const BROADCAST = 549755813888;
		const BLOCK_DOWNLOAD = 1099511627776;
		const REFUSE_CHAT = 2199023255552;
		const SPEAK_BEFORE = 4398046511104;
		const CHANGE_ICON = 8796093022208;
		const CHANGE_NICK = 17592186044416;
		const AWAY = 35184372088832;
		const FAKE_RED = 70368744177664;
		const SEND_MESSAGE = 140737488355328;
		const POST_BEFORE = 281474976710656;
		const ADM_IN_SPECTOR = 562949953421312;
		const DONT_QUEUE = 1125899906842624;
		const VIEW_OWN_DROP_BOX = 2251799813685248;
		const CAN_FLOOD = 4503599627370496;
		const CAN_VIEW_INVISIBLE = 9007199254740992;
		const VISIBLE = 18014398509481984;
	}
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.