ebb_prim.erl 2.9 KB

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