ebb_prim.erl 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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/3, 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, M, Map) ->
  40. Good = lists:all(fun({Source, Target}) when Source >= 1, Source =< N,
  41. Target >= 1, Target =< M ->
  42. true;
  43. ({_Source, _Target}) ->
  44. false
  45. end,
  46. Map),
  47. case Good of
  48. true -> #route{in=N, out=M, map=Map};
  49. false -> erlang:error(badarg, [N, M, Map])
  50. end.
  51. sync(N) when is_number(N) -> #sync{size=N}.
  52. split(N) when is_number(N) -> #split{size=N}.
  53. merge(N) when is_number(N) -> #merge{size=N}.
  54. switch(Map = [{_Tag1, Op1}|Rest]) ->
  55. In = in_arity(Op1),
  56. Out = out_arity(Op1),
  57. Match = lists:all(fun({_T_I, Op}) ->
  58. in_arity(Op) == In andalso out_arity(Op) == Out
  59. end,
  60. Rest),
  61. case Match of
  62. true -> #switch{in=1+In, out=Out, map=Map};
  63. false -> erlang:error(badarg, [Map])
  64. end.
  65. %%%-----------------------------------------------------------------------------
  66. %%% Operation querying
  67. %%%-----------------------------------------------------------------------------
  68. in_arity(#func{in=In}) -> In;
  69. in_arity(#value{}) -> 0;
  70. in_arity(#pipe{in=In}) -> In;
  71. in_arity(#par{in=In}) -> In;
  72. in_arity(#route{in=In}) -> In;
  73. in_arity(#sync{size=N}) -> N;
  74. in_arity(#split{}) -> 1;
  75. in_arity(#merge{size=N}) -> N;
  76. in_arity(#switch{in=In}) -> In.
  77. out_arity(#func{}) -> 1;
  78. out_arity(#value{}) -> 1;
  79. out_arity(#pipe{out=Out}) -> Out;
  80. out_arity(#par{out=Out}) -> Out;
  81. out_arity(#route{out=Out}) -> Out;
  82. out_arity(#sync{size=N}) -> N;
  83. out_arity(#split{size=N}) -> N;
  84. out_arity(#merge{}) -> 1;
  85. out_arity(#switch{out=Out}) -> Out.
  86. flatten_arity([First|Rest]) ->
  87. lists:foldl(fun(Op, {In, Out}) ->
  88. {In + in_arity(Op), Out + out_arity(Op)}
  89. end,
  90. {in_arity(First), out_arity(First)}, Rest).
  91. can_connect(Op1, Op2) ->
  92. case {out_arity(Op1), in_arity(Op2)} of
  93. {N, N} -> true;
  94. _ -> false
  95. end.