Last active
December 19, 2020 02:18
-
-
Save AustinEast/ece115ce4a5fe622b293be1b5c651101 to your computer and use it in GitHub Desktop.
Haxe Macro for defining unique IDs per Class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if macro | |
import haxe.macro.Type; | |
import haxe.macro.Context; | |
import haxe.macro.Expr; | |
#end | |
/** | |
* Implementing this interface on a Class will run `ClassID.build()`, then remove itself. | |
**/ | |
@:remove | |
@:autoBuild(ClassID.build()) | |
interface IClassID {} | |
class ClassID { | |
#if macro | |
static final types = new Map<ClassType,Int>(); | |
static final field_name = 'class_id'; | |
static final get_field_name = 'get_$field_name'; | |
static var uid = 0; | |
/** | |
* Generates the static variable `class_id`, which holds the unique Int ID for the defined Class. | |
* The non-static method `get_class_id()` is also generated so that Class instances can easily retrieve the Class ID. | |
*/ | |
public static function build():Array<Field> { | |
var fields = Context.getBuildFields(); | |
var pos = Context.currentPos(); | |
var ct = Context.getLocalClass().get(); | |
// If the Class doesn't have a Class ID, add one to the Map | |
if (!types.exists(ct)) types.set(ct, uid++); | |
// Add the `class_id` variable | |
fields.push({ | |
name: field_name, | |
kind: FVar(macro:Int, macro $v{types.get(ct)}), | |
access: [APublic, AStatic, AFinal], | |
pos: pos | |
}); | |
// If this Class extends another Class, recursively check if we need to override the `get_class_id()` method | |
var sc = ct.superClass; | |
while (sc != null) { | |
var sct = sc.t.get(); | |
for (field in sct.fields.get()) { | |
// Override the method if needed, then exit early | |
if (field.name == get_field_name) { | |
var concat = (macro class { | |
override function $get_field_name () return $p{ct.pack.concat([ct.name])}.$field_name; | |
}).fields; | |
return fields.concat(concat); | |
} | |
} | |
sc = sct.superClass; | |
} | |
// Otherwise add the `get_class_id()` method | |
var concat = (macro class { | |
public function $get_field_name () return $p{ct.pack.concat([ct.name])}.$field_name; | |
}).fields; | |
return fields.concat(concat); | |
} | |
#end | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ClassID; | |
class ClassA implements IClassID { | |
public function new() {} | |
} | |
class ClassB implements IClassID { | |
public function new() {} | |
} | |
// Test extending Classes | |
class ClassC extends ClassB {} | |
class ClassIDTest { | |
static function main() { | |
// Note - ID's will not be generated from Classes in any specific order, but they will still be unique. | |
// For example - although `ClassA` is defined first, it has an ID of 2 instead of 0. | |
trace(ClassA.class_id); // == 2 | |
trace(ClassB.class_id); // == 0 | |
trace(ClassC.class_id); // == 1 | |
trace(new ClassC().get_class_id()); // == 1 | |
trace(new ClassB().get_class_id()); // == 0 | |
trace(new ClassA().get_class_id()); // == 2 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment