ebb_prim.erl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. -module(ebb_prim).
  2. -include("../include/ebb_prim.hrl").
  3. %%% Operation construction
  4. -export([func/1, value/1,
  5. pipe/1, par/1,
  6. route/2, sync/1,
  7. split/1, merge/1,
  8. switch/1]).
  9. %%% Operation querying
  10. -export([is_operation/1,
  11. in_arity/1, out_arity/1,
  12. flatten_arity/1,
  13. can_connect/2]).
  14. %%%-----------------------------------------------------------------------------
  15. %%% Operation construction
  16. %%%-----------------------------------------------------------------------------
  17. func(F) when is_function(F) ->
  18. {arity, N} = erlang:fun_info(F, arity),
  19. #func{in=N, code=F}.
  20. value(X) -> #value{value=X}.
  21. pipe(Ops = [First|Rest]) ->
  22. try
  23. lists:foldl(fun(Op2, Op1) -> case is_operation(Op2) andalso
  24. can_connect(Op1, Op2) of
  25. true -> Op2;
  26. false -> throw(badarg)
  27. end
  28. end,
  29. case is_operation(First) of
  30. true -> First;
  31. false -> throw(badarg)
  32. end,
  33. Rest)
  34. of
  35. Last -> #pipe{in=in_arity(First), out=out_arity(Last), ops=Ops}
  36. catch
  37. throw:badarg -> erlang:error(badarg, [Ops])
  38. end.
  39. par(Ops = [_|_]) ->
  40. case lists:all(fun is_operation/1, Ops) of
  41. true -> ok;
  42. false -> erlang:error(badarg, [Ops])
  43. end,
  44. {In, Out} = flatten_arity(Ops),
  45. #par{in=In, out=Out, ops=Ops}.
  46. route(N, Map) when is_number(N) ->
  47. Good = lists:all(fun(Source) ->is_number(Source) andalso
  48. Source > 0 andalso Source =< N
  49. end,
  50. Map),
  51. case Good of
  52. true -> #route{in=N, out=length(Map), map=Map};
  53. false -> erlang:error(badarg, [N, Map])
  54. end.
  55. sync(N) when is_number(N) -> #sync{size=N}.
  56. split(N) when is_number(N) -> #split{size=N}.
  57. merge(N) when is_number(N) -> #merge{size=N}.
  58. switch(Map = [{_Tag1, Op1}|Rest]) ->
  59. In = in_arity(Op1),
  60. Out = out_arity(Op1),
  61. Match = lists:all(
  62. fun({_T_I, Op}) ->
  63. is_operation(Op) andalso
  64. in_arity(Op) == In andalso out_arity(Op) == Out
  65. end,
  66. Rest),
  67. case Match of
  68. true -> #switch{in=1+In, out=Out, map=Map};
  69. false -> erlang:error(badarg, [Map])
  70. end.
  71. %%%-----------------------------------------------------------------------------
  72. %%% Operation querying
  73. %%%-----------------------------------------------------------------------------
  74. is_operation(#func{}) -> true;
  75. is_operation(#value{}) -> true;
  76. is_operation(#pipe{}) -> true;
  77. is_operation(#par{}) -> true;
  78. is_operation(#route{}) -> true;
  79. is_operation(#sync{}) -> true;
  80. is_operation(#split{}) -> true;
  81. is_operation(#merge{}) -> true;
  82. is_operation(#switch{}) -> true;
  83. is_operation(_) -> false.
  84. in_arity(#func{in=In}) -> In;
  85. in_arity(#value{}) -> 0;
  86. in_arity(#pipe{in=In}) -> In;
  87. in_arity(#par{in=In}) -> In;
  88. in_arity(#route{in=In}) -> In;
  89. in_arity(#sync{size=N}) -> N;
  90. in_arity(#split{}) -> 1;
  91. in_arity(#merge{size=N}) -> N;
  92. in_arity(#switch{in=In}) -> In.
  93. out_arity(#func{}) -> 1;
  94. out_arity(#value{}) -> 1;
  95. out_arity(#pipe{out=Out}) -> Out;
  96. out_arity(#par{out=Out}) -> Out;
  97. out_arity(#route{out=Out}) -> Out;
  98. out_arity(#sync{size=N}) -> N;
  99. out_arity(#split{size=N}) -> N;
  100. out_arity(#merge{}) -> 1;
  101. out_arity(#switch{out=Out}) -> Out.
  102. flatten_arity([First|Rest]) ->
  103. lists:foldl(fun(Op, {In, Out}) ->
  104. {In + in_arity(Op), Out + out_arity(Op)}
  105. end,
  106. {in_arity(First), out_arity(First)}, Rest).
  107. can_connect(Op1, Op2) ->
  108. case {out_arity(Op1), in_arity(Op2)} of
  109. {N, N} -> true;
  110. _ -> false
  111. end.