Reputation: 61
Let's say I want to create a generic inline function in Haxe that takes flash ByteArray
and an Array
.
@:generic public static inline function WriteArray<T:(UInt, Int, Float)>(ba:ByteArray, array:Array<T>):Void
{
if (array == null)
{
ba.writeInt(-1);
}
else
{
ba.writeInt(array.length);
for (i in 0...array.length)
{
// here is where I have a problem
// ba.writeUnsignedInt(array[i]); if T is UInt
// ba.writeDouble(array[i]); if T is Float
// ba.writeInt(array[i]); if T is Int
}
}
}
So, I need some way to get each of the generated functions to use a different line there. This code needs to be performant, so doing runtime checks for type isn't an option. I also can't pass in which write function to use as parameter (writeFunc:T->Void
) b/c we're currently compiling to Flash, and Flash creates a MethodClosure
object every time you make a reference to a function, and the garbage collector doesn't handle them well (this happens whether the function is inline or not). I've also tried to use macros, but you can't use anything from the flash library inside a macro (I have a similar function for writing flash vectors, and we're still using flash's ByteArray
implementation). I'm hoping there's a way to get T
at compile time, but all I've found is ${type}
and I don't think you can use that conditionally.
So, is there a way to get that function to call the correct write method on the ByteArray
without creating a reference to that function? It doesn't necessarily have to use @:generic
, but I figure the constraints would be helpful. Other implementation ideas would also be welcome. Right now I've just got 3 versions of the same function, and c/p'd code just about makes me throw up in my mouth.
Upvotes: 3
Views: 71
Reputation: 34138
I've also tried to use macros, but you can't use anything from the flash library inside a macro
That's not entirely true: you can't actually use flash API in a macro, but you can generate code that uses it. You just need to make sure not to add it as an import
-statement at the top of the file and use the fully qualified name (flash.utils.ByteArray
) instead.
Here's a simple example:
import haxe.macro.Context;
import haxe.macro.Expr.Access;
import haxe.macro.Expr.FieldType;
class Macro {
public static function build() {
var fields = Context.getBuildFields();
fields.push({
name: "byteArray",
access: [Access.APublic, Access.AStatic],
kind: FieldType.FVar(macro:flash.utils.ByteArray, null),
pos: Context.currentPos(),
});
return fields;
}
}
...which generates:
public static var byteArray:flash.utils.ByteArray;
Upvotes: 4