COMMUNITY

Best way to create an enum abstract value from string?

When using standard enums, it’s easy to create an enum value from a string using the createByName() method:

enum MyEnum {
	Alt1;
}
var alt1 = MyEnum.createByName('Alt1');

How can I do the same using enum abstracts?
Let’s say I have following…

enum abstract MyAbstractEnum(Int) {
	var Alt1 = 1;
}

…where I would like to create the MyAbstractEnum.Alt1 from the string “Alt1”?

Has to be done the macro way because abstracts don’t exist at runtime, right?
This code.haxe.org snippet helps me getting the underlying values, and by modifying that snippet I can also get the field names… But I haven’t figured out the rest.

Ideas?

/ Jonas

You can generate a similar code with macros.

enum abstract MyAbstractEnum(Int) {
	var Alt1 = 1;
    
    public static function fromStr(str: String): MyAbstractEnum
    {
       	return switch (str)
        {
                case "Alt1": Alt1;
                default: null;
        }
	}
 }
...
var value = MyAbstractEnum.fromStr("Alt1");

Thanks, Alexander, but I want to avoid a string switch like that - If there is twenty or a hundred values in the enum abstract, the problems become obvious.

Maybe, this variant:

class AbstractEnumTools 
{

    public static macro function getValueMap(typePath: Expr):  Expr
    {
        var type = Context.getType(typePath.toString());
        switch (type.follow()) 
        {
            case TAbstract(_.get() => ab, _) if (ab.meta.has(":enum")):
            var map : Array<Expr> = [];
            for (field in ab.impl.get().statics.get()) 
            {
                if (field.meta.has(":enum") && field.meta.has(":impl")) 
                {
                    var fieldName = field.name;
                    var value = macro $typePath.$fieldName;
                    map.push(macro $v{fieldName} => $value);
                }
            }
            return macro $a{map};

            default:
                    throw new Error(type.toString() + " should be @:enum abstract", typePath.pos);
        }
    }
}

enum abstract MyAbstractEnum(Int) 
{
	var Alt1 = 1;
    public static function fromStr(str: String): MyAbstractEnum
    {
        var valueMap = AbstractEnumTools.getValueMap(MyAbstractEnum);
        return valueMap[str];
    }
}
1 Like

You can use a string map instead

Thanks, Alexander!

Yes, that’s a working solution, and a great addition to Dan’s AbstractEnumTools.