Skip to content

Commit e7092db

Browse files
committed
Extract common code
1 parent 1076896 commit e7092db

File tree

4 files changed

+133
-176
lines changed

4 files changed

+133
-176
lines changed

src/why/pubsub/Macro.hx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package why.pubsub;
2+
3+
import haxe.ds.Option;
4+
import haxe.macro.Expr;
5+
import haxe.macro.Type;
6+
7+
using tink.MacroApi;
8+
9+
class Macro {
10+
11+
public static function getFields(type:Type, kind:PubSubKind, pos:Position):Array<Entry> {
12+
return switch type {
13+
case TInst(_.get() => {isInterface: true, fields: _.get() => fields}, _):
14+
[for(f in fields) {
15+
if(!f.meta.has(':compilerGenerated')) {
16+
switch [f.kind, f.type] {
17+
case [FVar(AccCall, AccNever | AccNo), TInst(_.get() => {pack: ['why', 'pubsub'], name: name}, [msg])] if ((kind:String) == name):
18+
{
19+
field: f,
20+
type: msg,
21+
variant: Prop,
22+
}
23+
case [FMethod(_), TFun(args, TInst(_.get() => {pack: ['why', 'pubsub'], name: name}, [msg]))] if ((kind:String) == name):
24+
{
25+
field: f,
26+
type: msg,
27+
variant: Func(args),
28+
}
29+
case [FVar(AccCall, AccNever | AccNo), v] | [FMethod(_), TFun(_, v)]:
30+
f.pos.error('Only why.pubsub.$kind<T> is supported here but got (${v.getID()})');
31+
case _:
32+
f.pos.error('Only var(get, never/null) or function is supported here');
33+
}
34+
}
35+
}];
36+
case _:
37+
pos.error('Expected interface');
38+
}
39+
}
40+
41+
public static function getMetaWithOneParam(field:ClassField, name:String):Option<Expr> {
42+
return switch field.meta.extract(name) {
43+
case []:
44+
None;
45+
case [{params: [expr]}]:
46+
Some(expr);
47+
case [{pos: pos}]:
48+
pos.error('$name requires exactly one parameter');
49+
case _:
50+
field.pos.error('Only one $name is allowed');
51+
}
52+
}
53+
54+
public static function populate(def:TypeDefinition, fields:Array<Entry>, kind:PubSubKind, getFactory:Entry->Expr) {
55+
for(f in fields) {
56+
var name = f.field.name;
57+
var msgCt = f.type.toComplex();
58+
var factory = getFactory(f);
59+
60+
switch f.variant {
61+
case Prop:
62+
var ct = f.field.type.toComplex();
63+
var getter = 'get_$name';
64+
def.fields = def.fields.concat((macro class {
65+
public var $name(get, null):$ct;
66+
function $getter():$ct {
67+
if($i{name} == null)
68+
$i{name} = $factory;
69+
return $i{name};
70+
}
71+
}).fields);
72+
73+
case Func(args):
74+
var ct = macro:why.pubsub.$kind<$msgCt>;
75+
76+
var body = switch getMetaWithOneParam(f.field, ':why.pubsub.cache') {
77+
case Some(cache):
78+
var cacheName = '__cache_$name';
79+
def.fields.push({
80+
name: cacheName,
81+
access: [],
82+
kind: FVar(macro:why.pubsub.Cache<String, $ct>, macro new why.pubsub.Cache.StringCache()),
83+
pos: f.field.pos,
84+
});
85+
86+
macro {
87+
var cache = $cache;
88+
var key = cache.key;
89+
$i{cacheName}.get(key, _ -> $factory);
90+
}
91+
case None:
92+
factory;
93+
}
94+
var func = body.func(args.map(arg -> arg.name.toArg(arg.t.toComplex(), arg.opt)), ct);
95+
def.fields.push({
96+
name: name,
97+
access: [APublic],
98+
kind: FFun(func),
99+
pos: f.field.pos,
100+
});
101+
}
102+
}
103+
}
104+
}
105+
106+
enum abstract PubSubKind(String) to String {
107+
var Publisher = 'Publisher';
108+
var Subscriber = 'Subscriber';
109+
}
110+
111+
typedef Entry = {
112+
field:ClassField,
113+
type:Type,
114+
variant:Variant,
115+
}
116+
117+
enum Variant {
118+
Prop;
119+
Func(args:Array<{name:String, opt:Bool, t:Type}>);
120+
}

src/why/pubsub/rabbitmq/Helper.hx

Lines changed: 3 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,17 @@
11
package why.pubsub.rabbitmq;
22

3-
import haxe.ds.Option;
43
import haxe.macro.Expr;
54
import haxe.macro.Type;
65

76
using tink.MacroApi;
87

98
class Helper {
10-
11-
public static function getFields(type:Type, name:String, pos:Position):Array<Entry> {
12-
return switch type {
13-
case TInst(_.get() => {isInterface: true, fields: _.get() => fields}, _):
14-
[for(f in fields) {
15-
if(!f.meta.has(':compilerGenerated')) {
16-
switch [f.kind, f.type] {
17-
case [FVar(AccCall, AccNever | AccNo), TInst(_.get() => {pack: ['why', 'pubsub'], name: n}, [msg])] if (n == name):
18-
{
19-
field: f,
20-
type: msg,
21-
variant: Prop,
22-
}
23-
case [FMethod(_), TFun(args, TInst(_.get() => {pack: ['why', 'pubsub'], name: n}, [msg]))] if (n == name):
24-
{
25-
field: f,
26-
type: msg,
27-
variant: Func(args),
28-
}
29-
case [FVar(AccCall, AccNever | AccNo), v] | [FMethod(_), TFun(_, v)]:
30-
f.pos.error('Only why.pubsub.$name<T> is supported here but got (${v.getID()})');
31-
case _:
32-
f.pos.error('Only var(get, never/null) or function is supported here');
33-
}
34-
}
35-
}];
36-
case _:
37-
pos.error('Expected interface');
38-
}
39-
}
40-
419
public static function getConfig(field:ClassField):Expr {
42-
return switch field.meta.extract(':why.pubsub.rabbitmq') {
43-
case []:
10+
return switch Macro.getMetaWithOneParam(field, ':why.pubsub.rabbitmq') {
11+
case None:
4412
field.pos.error('Missing config via meta @:why.pubsub.rabbitmq');
45-
case [{params: [expr]}]:
13+
case Some(expr):
4614
expr;
47-
case [{pos: pos}]:
48-
pos.error('@:why.pubsub.rabbitmq requires exactly one parameter');
49-
case _:
50-
field.pos.error('Only one @:why.pubsub.rabbitmq is allowed');
51-
}
52-
}
53-
54-
public static function getCache(field:ClassField):Option<Expr> {
55-
return switch field.meta.extract(':why.pubsub.cache') {
56-
case []:
57-
None;
58-
case [{params: [expr]}]:
59-
Some(macro ($expr:why.pubsub.Cache.CacheConfig<String>));
60-
case [{pos: pos}]:
61-
pos.error('@:why.pubsub.cache requires exactly one parameter');
62-
case _:
63-
field.pos.error('Only one @:why.pubsub.cache is allowed');
6415
}
6516
}
6617
}
67-
68-
typedef Entry = {
69-
field:ClassField,
70-
type:Type,
71-
variant:Variant,
72-
}
73-
74-
enum Variant {
75-
Prop;
76-
Func(args:Array<{name:String, opt:Bool, t:Type}>);
77-
}

src/why/pubsub/rabbitmq/Publishers.macro.hx

Lines changed: 5 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,73 +10,22 @@ class Publishers {
1010
public static function build() {
1111
return BuildCache.getType('why.pubsub.rabbitmq.Publishers', (ctx:BuildContext) -> {
1212
var name = ctx.name;
13-
var type = ctx.type;
14-
var ct = type.toComplex();
15-
var tp = switch ct {
13+
var tp = switch ctx.type.toComplex() {
1614
case TPath(v): v;
1715
case _: throw 'assert';
1816
}
1917

20-
var fields = getFields(ctx.type, ctx.pos);
21-
2218
var def = macro class $name extends why.pubsub.rabbitmq.Publishers.PublishersBase implements $tp {}
2319

24-
for(f in fields) {
25-
var name = f.field.name;
20+
var fields = Macro.getFields(ctx.type, Publisher, ctx.pos);
21+
Macro.populate(def, fields, Publisher, f -> {
2622
var msgCt = f.type.toComplex();
27-
2823
var config = macro (${Helper.getConfig(f.field)}:why.pubsub.rabbitmq.Publisher.PublisherConfig<$msgCt>);
29-
30-
switch f.variant {
31-
case Prop:
32-
var ct = f.field.type.toComplex();
33-
var getter = 'get_$name';
34-
def.fields = def.fields.concat((macro class {
35-
public var $name(get, null):$ct;
36-
function $getter():$ct {
37-
if($i{name} == null)
38-
$i{name} = new why.pubsub.rabbitmq.Publisher(manager, $config);
39-
return $i{name};
40-
}
41-
}).fields);
42-
43-
case Func(args):
44-
var ct = macro:why.pubsub.Publisher<$msgCt>;
45-
46-
var body = switch Helper.getCache(f.field) {
47-
case Some(cache):
48-
var cacheName = '__cache_$name';
49-
def.fields.push({
50-
name: cacheName,
51-
access: [],
52-
kind: FVar(macro:why.pubsub.Cache<String, $ct>, macro new why.pubsub.Cache.StringCache()),
53-
pos: f.field.pos,
54-
});
55-
56-
macro {
57-
var cache = $cache;
58-
var key = cache.key;
59-
$i{cacheName}.get(key, _ -> new why.pubsub.rabbitmq.Publisher(manager, $config));
60-
}
61-
case None:
62-
macro new why.pubsub.rabbitmq.Publisher(manager, $config);
63-
}
64-
var func = body.func(args.map(arg -> arg.name.toArg(arg.t.toComplex(), arg.opt)), ct);
65-
def.fields.push({
66-
name: name,
67-
access: [APublic],
68-
kind: FFun(func),
69-
pos: f.field.pos,
70-
});
71-
}
72-
}
24+
macro new why.pubsub.rabbitmq.Publisher(manager, $config);
25+
});
7326

7427
def.pack = ['why', 'pubsub', 'rabbitmq'];
7528
def;
7629
});
7730
}
78-
79-
static function getFields(type:Type, pos:Position) {
80-
return Helper.getFields(type, 'Publisher', pos);
81-
}
8231
}

src/why/pubsub/rabbitmq/Subscribers.macro.hx

Lines changed: 5 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,74 +11,22 @@ class Subscribers {
1111
public static function build() {
1212
return BuildCache.getType('why.pubsub.rabbitmq.Subscribers', (ctx:BuildContext) -> {
1313
var name = ctx.name;
14-
var type = ctx.type;
15-
var ct = type.toComplex();
16-
var tp = switch ct {
14+
var tp = switch ctx.type.toComplex() {
1715
case TPath(v): v;
1816
case _: throw 'assert';
1917
}
2018

21-
var fields = getFields(ctx.type, ctx.pos);
22-
2319
var def = macro class $name extends why.pubsub.rabbitmq.Subscribers.SubscribersBase implements $tp {}
2420

25-
for(f in fields) {
26-
var name = f.field.name;
21+
var fields = Macro.getFields(ctx.type, Subscriber, ctx.pos);
22+
Macro.populate(def, fields, Subscriber, f -> {
2723
var msgCt = f.type.toComplex();
28-
2924
var config = macro (${Helper.getConfig(f.field)}:why.pubsub.rabbitmq.Subscriber.SubscriberConfig<$msgCt>);
30-
31-
32-
switch f.variant {
33-
case Prop:
34-
var ct = f.field.type.toComplex();
35-
var getter = 'get_$name';
36-
def.fields = def.fields.concat((macro class {
37-
public var $name(get, null):$ct;
38-
function $getter():$ct {
39-
if($i{name} == null)
40-
$i{name} = new why.pubsub.rabbitmq.Subscriber(manager, $config);
41-
return $i{name};
42-
}
43-
}).fields);
44-
45-
case Func(args):
46-
var ct = macro:why.pubsub.Subscriber<$msgCt>;
47-
48-
var body = switch Helper.getCache(f.field) {
49-
case Some(cache):
50-
var cacheName = '__cache_$name';
51-
def.fields.push({
52-
name: cacheName,
53-
access: [],
54-
kind: FVar(macro:why.pubsub.Cache<String, $ct>, macro new why.pubsub.Cache.StringCache()),
55-
pos: f.field.pos,
56-
});
57-
58-
macro {
59-
var cache = $cache;
60-
var key = cache.key;
61-
$i{cacheName}.get(key, _ -> new why.pubsub.rabbitmq.Subscriber(manager, $config));
62-
};
63-
case None:
64-
macro new why.pubsub.rabbitmq.Subscriber(manager, $config);
65-
}
66-
var func = body.func(args.map(arg -> arg.name.toArg(arg.t.toComplex(), arg.opt)), ct);
67-
def.fields.push({
68-
name: name,
69-
access: [APublic],
70-
kind: FFun(func),
71-
pos: f.field.pos,
72-
});
73-
}
74-
}
25+
macro new why.pubsub.rabbitmq.Subscriber(manager, $config);
26+
});
7527

7628
def.pack = ['why', 'pubsub', 'rabbitmq'];
7729
def;
7830
});
7931
}
80-
81-
static function getFields(type:Type, pos:Position) {
82-
return Helper.getFields(type, 'Subscriber', pos);
83-
}
8432
}

0 commit comments

Comments
 (0)