JREnum icon indicating copy to clipboard operation
JREnum copied to clipboard

macros that automate vending an NSString given an enum value (f.x. MyEnumToString(value))

JREnum

Original idea and implementation by Benedict Cohen.

JREnum is a macro that automates creation of functions that blast enums from boring primitive compile-time-land to the fun-filled party environment of runtime.

Let's use a concrete example. Instead of writing:

typedef enum {
    Stream_Disconnected,
    Stream_Connecting,
    Stream_Connected,
    Stream_Disconnecting
}   StreamState;

write:

JREnum(StreamState,
       Stream_Disconnected,
       Stream_Connecting,
       Stream_Connected,
       Stream_Disconnecting);

This will generate the previous typedef enum and will also generate a corresponding suite of functions:

NSString* StreamStateToString(int value)

Given a value, will return the enum's string representation. For example StreamStateToString(2) would return @"Stream_Connected".

When confronted with values not defined in the enumeration, this function will return a placeholder string explaining the situation. For example StreamStateToString(2000) would return @"<unknown StreamState: 2000>".

BOOL StreamStateFromString(NSString *enumLabel, StreamState *enumValue)

Attempts to return the enum's int value given its label. For example StreamStateFromString(@"Stream_Disconnecting", &value) would return YES and set value to 3.

This function returns NO if the label for the enum type is unknown. For example StreamStateFromString(@"lackadaisical", &value) would return NO and leave value untouched.

NSDictionary* StreamStateByValue()

Returns a dictionary whose keys are the enum's values. Used by StreamStateToString().

When enums have multiple overlapping values, the current implementation exhibits last-write-wins behavior.

NSDictionary* StreamStateByLabel()

Returns a dictionary whose keys are the enum's labels. Used by StreamStateFromString(). This is the function you want if you wish to enumerate an enum's labels and values at runtime.

Split Header / Source Files

JREnum() is fine for when you have an enum that lives solely in an .m file. But if you're exposing an enum in a header file, you'll have to use the alternate macros. In your .h, use JREnumDeclare():

JREnumDeclare(StreamState,
              Stream_Disconnected,
              Stream_Connecting,
              Stream_Connected,
              Stream_Disconnecting);

And then use JREnumDefine() in your .m:

JREnumDefine(StreamState);

Explicit Values

You can also explicitly define enum integer values:

JREnum(StreamState,
       Stream_Disconnected = 42,
       Stream_Connecting,
       Stream_Connected,
       Stream_Disconnecting);

In the above scenario, Stream_Disconnected's value will be 42, Stream_Connecting's will be 43 and so on.

You can also use hex values:

JREnum(StreamState,
       Stream_Disconnected = 0x2A,
       Stream_Connecting,
       Stream_Connected,
       Stream_Disconnecting);

That's semantically identical to the above.

New in v1.1 you can use very simple bit-shift masks:

JREnum(Align,
	   AlignLeft         = 1 << 0,
	   AlignRight        = 1 << 1,
	   AlignTop          = 1 << 2,
	   AlignBottom       = 1 << 3,
	   AlignTopLeft      = 0x05,
	   AlignBottomLeft   = 0x09,
	   AlignTopRight     = 0x06,
	   AlignBottomRight  = 0x0A,
	   );

This helps where you want one variable to house a combination of flags:

Align botRight 		  = AlignBottomRight;
Align botRightBitWise = AlignBottom | AlignRight;

NSLog(@"Are They The Same: %@", (botRightBitWise == botRight) ? @"YES" : @"NO");
//=> Are They The Same: YES

But better, because you can go to-and-fro string values:

NSLog(@"How is that combo aligned? %@", AlignToString(botRightBitWise));
//=> How is that combo aligned? AlignBottomRight

TODO

Version History

v1.2: Jul 4 2017

v1.1: Mar 25 2014

  • [NEW] Add support for hex constants. (Alex Gray)
  • [NEW] Add support for very simple bit-shifting constants. (rentzsch)

v1.0.1: May 28 2013

v1.0: Apr 09 2013

  • Minor bug fix from 0.2.

v0.2: Dec 10 2012

  • [NEW] Generalized to support bidirectional enum label/value lookup and full runtime access to lookup dictionary.
  • [NEW] Add passing tests.
  • [NEW] Write this README.

v0.1: Dec 9 2012

  • [NEW] Devised way to allow split declaration/definition macros to allow use in header/source files.

Prelude: Dec 8 2012