Skip to content

Instantly share code, notes, and snippets.

@back2dos
Forked from nadako/ArrayRead.hx
Last active September 29, 2017 01:02
Show Gist options
  • Save back2dos/1ec3c0977ac8e5893dc9274609e23f3d to your computer and use it in GitHub Desktop.
Save back2dos/1ec3c0977ac8e5893dc9274609e23f3d to your computer and use it in GitHub Desktop.
Recursive read-only type generator for JSON structures (based on @:genericBuild)
@:forward(map, filter, copy, slice)
abstract ArrayRead<T>(Array<T>) from Array<T> to Iterable<T> {
@:arrayAccess inline function get(i:Int):T return this[i];
public var length(get,never):Int;
inline function get_length() return this.length;
}
@:genericBuild(ConstMacro.build())
class Const<T> {}
package ;
import haxe.macro.Context;
import haxe.macro.Type;
import haxe.macro.Expr;
using haxe.macro.Tools;
using tink.MacroApi;
using StringTools;
class ConstMacro {
static function build()
return switch Context.getLocalType() {
case TInst(_.get() => {pack: [], name: "Const"}, [t]):
rec(t);
default:
throw false;
}
static var cache = new tink.macro.TypeMap(true);
static function rec(t:Type):ComplexType {
return switch cache.get(t) {
case null:
var ret =
switch t {
case TType(_.get() => alias, params) if (t.getID() == null):
var ct = t.reduce().toComplex(),
name = 'Const<${t.toString().replace(".", "_")}>';
for (p in params) switch p {
case TInst(_.get() => { kind: KTypeParameter(_), name: name }, _):
Context.currentPos().error('Cannot ensure `Const` for unapplied type parameter $name');
default: continue;
}
Context.defineType({
pack: [],
name: name,
pos: alias.pos,
kind: TDAlias(macro : Const<$ct>),
fields: [],
});
name.asComplexType();
case _.getID() => 'Int' | 'String' | 'Float' | 'Bool' | 'Date': t.toComplex();
case _.reduce() => TInst(_.get() => { pack: [], name: 'Array' }, [t]):
var ct = rec(t);
macro : ArrayRead<$ct>;
default:
TAnonymous([
for (f in t.getFields().sure()) {
name: f.name,
pos: f.pos,
meta: f.meta.get(),
kind: FProp(
'default',
'never',
rec(f.type)
)
}
]);
}
cache.set(t, ret);
ret;
case v: v;
}
}
}
class Main {
static function main() {
var a:Const<Array<House>> = [];
a[0].tenants[1] = {name: "Dan"}; // No @:arrayAccess function accepts arguments of Int and { name : String }
a[0].tenants[1].name = "Dan"; // Cannot access field or identifier name for writing
}
}
typedef House = {
itemId:Int,
typeId:String,
tenants:Array<{name:String}>,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment