diff --git a/lib/exactor/common.ex b/lib/exactor/common.ex new file mode 100644 index 0000000..fb0204d --- /dev/null +++ b/lib/exactor/common.ex @@ -0,0 +1,22 @@ +defmodule ExActor.Common do + @moduledoc false + + # This module adds common functionality to all ExActor behaviours. + defmacro __using__(_opts) do + quote do + @doc """ + By default, the `server` argument given + to the different interface functions, is expected to be a process identifier, + unless overridden by the `export:` option. + + But by providing a custom implementation of `server_pid/1`, you can map an identifier + to a PID by some other means. + """ + def server_pid(server_reference) do + server_reference + end + + defoverridable [server_pid: 1] + end + end +end diff --git a/lib/exactor/empty.ex b/lib/exactor/empty.ex index abe0c69..bc6b312 100644 --- a/lib/exactor/empty.ex +++ b/lib/exactor/empty.ex @@ -21,6 +21,7 @@ defmodule ExActor.Empty do defmacro __using__(opts) do quote do @behaviour :gen_server + use ExActor.Common @generated_funs MapSet.new diff --git a/lib/exactor/gen_server.ex b/lib/exactor/gen_server.ex index 7607c58..2a358cb 100644 --- a/lib/exactor/gen_server.ex +++ b/lib/exactor/gen_server.ex @@ -19,6 +19,7 @@ defmodule ExActor.GenServer do defmacro __using__(opts) do quote do use GenServer + use ExActor.Common @generated_funs MapSet.new diff --git a/lib/exactor/operations.ex b/lib/exactor/operations.ex index efd9f3f..2375191 100644 --- a/lib/exactor/operations.ex +++ b/lib/exactor/operations.ex @@ -570,7 +570,8 @@ defmodule ExActor.Operations do server_fun: server_fun(type), interface_args: Macro.escape(interface_args(interface_matches, options), unquote: true), gen_server_args: Macro.escape(gen_server_args(options, type, payload), unquote: true), - guard: Macro.escape(guard(options, :interface), unquote: true) + guard: Macro.escape(guard(options, :interface), unquote: true), + export_option: Macro.escape(options[:export], unquote: true) ] do {interface_args, gen_server_args} = unless type in [:multicall, :abcast] do @@ -582,31 +583,32 @@ defmodule ExActor.Operations do } end - arity = length(interface_args) - unless private do - if guard do - def unquote(req_name)(unquote_splicing(interface_args)) - when unquote(guard) - do - GenServer.unquote(server_fun)(unquote_splicing(gen_server_args)) - end + interface_gen_server_args = + if type in [:multicall, :abcast] || export_option do + gen_server_args else - def unquote(req_name)(unquote_splicing(interface_args)) do - GenServer.unquote(server_fun)(unquote_splicing(gen_server_args)) - end - end - else - if guard do - defp unquote(req_name)(unquote_splicing(interface_args)) - when unquote(guard) - do - GenServer.unquote(server_fun)(unquote_splicing(gen_server_args)) - end - else - defp unquote(req_name)(unquote_splicing(interface_args)) do - GenServer.unquote(server_fun)(unquote_splicing(gen_server_args)) - end + # Extract the server reference as first argument, + # And call `server_pid/1` on it inside the interface implementation. + # (But not in the function head) + [server_ref | gen_server_args_tail] = gen_server_args + server_pid_quote = quote(do: server_pid(unquote(server_ref))) + [server_pid_quote | gen_server_args_tail] end + + interface_body = + quote do + GenServer.unquote(server_fun)(unquote_splicing(interface_gen_server_args)) + end + + cond do + private == nil && guard == nil -> + def unquote(req_name)(unquote_splicing(interface_args)), do: unquote(interface_body) + private == nil && guard != nil -> + def unquote(req_name)(unquote_splicing(interface_args)) when unquote(guard), do: unquote(interface_body) + private != nil && guard == nil -> + defp unquote(req_name)(unquote_splicing(interface_args)), do: unquote(interface_body) + private != nil && guard != nil -> + defp unquote(req_name)(unquote_splicing(interface_args)) when unquote(guard), do: unquote(interface_body) end end end diff --git a/lib/exactor/strict.ex b/lib/exactor/strict.ex index 5b201bc..d551c20 100644 --- a/lib/exactor/strict.ex +++ b/lib/exactor/strict.ex @@ -28,6 +28,7 @@ defmodule ExActor.Strict do defmacro __using__(opts) do quote do use ExActor.Behaviour.Strict + use ExActor.Common @generated_funs MapSet.new diff --git a/lib/exactor/tolerant.ex b/lib/exactor/tolerant.ex index d7fb6b5..37eea9b 100644 --- a/lib/exactor/tolerant.ex +++ b/lib/exactor/tolerant.ex @@ -23,6 +23,7 @@ defmodule ExActor.Tolerant do defmacro __using__(opts) do quote do use ExActor.Behaviour.Tolerant + use ExActor.Common @generated_funs MapSet.new