🔧

Haxeでabstract enumに値が存在するかを判定するマクロ

2024/05/31に公開

Get all values of an @:enum abstract - Macros - Haxe programming language cookbook の改編版。

例えばこんな感じのabstract enumにsha1が存在するかを判定するのに使う。

// hxnodejsから拝借
// https://github.com/HaxeFoundation/hxnodejs/blob/c9450595b2337587bcdaeacf159019531925f25d/src/js/node/Crypto.hx#L39C1-L45C1
enum abstract CryptoAlgorithm(String) from String to String {
    var SHA1 = "sha1";
    var MD5 = "md5";
    var SHA256 = "sha256";
    var SHA512 = "sha512";
}
#if macro
import haxe.macro.Context;
import haxe.macro.Expr;

using haxe.macro.Tools;
#end

/**
    `enum abstract` 型に指定した値が存在するかを判定する switch 式を生成します。
**/
macro function containsAbstractEnumValue(typePath:Expr, value:Expr):ExprOf<Bool> {
    final type = Context.getType(typePath.toString());
    switch (type.follow()) {
        case TAbstract(_.get() => ab, _) if (ab.meta.has(":enum")):
            final cases:Array<Case> = [];
            for (field in ab.impl.get().statics.get()) {
                if (field.meta.has(":enum") && field.meta.has(":impl")) {
                    final fieldName = field.name;
                    cases.push({ values: [macro $typePath.$fieldName], expr: macro true });
                }
            }

            return {
                pos: Context.currentPos(),
                expr: ESwitch(value, cases, macro false)
            };
        default:
            throw new Error(type.toString() + " should be enum abstract", typePath.pos);
    }
}

使用側

final result = containsAbstractEnumValue(CryptoAlgorithm, "sha1");
trace(result); //true

マクロとしては、abstract enumの型定義からtrueを返すswitch式を作ってるだけ。

try haxeで動作確認したので、こちらも貼っておきます。

https://try.haxe.org/#CA46Fb6a

Discussion