%%%------------------------------------------------------------------- %%% @doc %%% Common Shards Utilities. %%% @end %%%------------------------------------------------------------------- -module(shards_lib). %% API -export([ object_key/2, get_sup_child/2, keyfind/2, keyfind/3, keyupdate/3, keyupdate/4, keypop/2, keypop/3, to_string/1, read_tabfile/1, write_tabfile/2 ]). -type kv_list() :: [{term(), term()}]. -export_type([kv_list/0]). %%%=================================================================== %%% API %%%=================================================================== %% @doc %% Returns the key for the given object or list of objects. %% @end -spec object_key(ObjOrObjs, Meta) -> term() when ObjOrObjs :: tuple() | [tuple()], Meta :: shards_meta:t(). object_key(ObjOrObjs, Meta) when is_tuple(ObjOrObjs) -> element(shards_meta:keypos(Meta), ObjOrObjs); object_key(ObjOrObjs, Meta) when is_list(ObjOrObjs) -> element(shards_meta:keypos(Meta), hd(ObjOrObjs)). %% @doc %% Searches the childern of the supervisor `SupPid' for a child whose Nth %% element compares equal to `Id'. %% @end -spec get_sup_child(SupPid, Id) -> Child when SupPid :: pid(), Id :: term(), Child :: pid() | undefined | restarting. get_sup_child(SupPid, Id) -> {Id, Child, _, _} = lists:keyfind(Id, 1, supervisor:which_children(SupPid)), Child. %% @equiv keyfind(Key, KVList, undefined) keyfind(Key, KVList) -> keyfind(Key, KVList, undefined). %% @doc %% Returns the value to the given `Key' or `Default' if it doesn't exist. %% @end -spec keyfind(term(), kv_list(), term()) -> term(). keyfind(Key, KVList, Default) -> case lists:keyfind(Key, 1, KVList) of {Key, Value} -> Value; _ -> Default end. %% @equiv keyupdate(Fun, Keys, undefined, TupleList) keyupdate(Fun, Keys, TupleList) -> keyupdate(Fun, Keys, undefined, TupleList). %% @doc %% Updates the given `Keys' by the result of calling `Fun(OldValue)'. %% If `Key' doesn't exist, then `Init' is set. %% @end -spec keyupdate(Fun, Keys, Init, KVList1) -> KVList2 when Fun :: fun((Key :: term(), Value :: term()) -> term()), Keys :: [term()], Init :: term(), KVList1 :: kv_list(), KVList2 :: kv_list(). keyupdate(Fun, Keys, Init, KVList1) when is_function(Fun, 2) -> lists:foldl(fun(Key, Acc) -> NewKV = case lists:keyfind(Key, 1, Acc) of {Key, Value} -> {Key, Fun(Key, Value)}; false -> {Key, Init} end, lists:keystore(Key, 1, Acc, NewKV) end, KVList1, Keys). %% @equiv keypop(Key, KVList1, undefined) keypop(Key, KVList1) -> keypop(Key, KVList1, undefined). %% @doc %% Searches the list of tuples `KVList1' for a tuple whose Nth element %% compares equal to `Key'. Returns `{Value, KVList2}' if such a tuple %% is found, otherwise `{Default, KVList1}'. `KVList2' is a copy of %% `KVList1' where the first occurrence of Tuple has been removed. %% @end -spec keypop(Key, KVList1, Default) -> {Value, KVList2} when Key :: term(), KVList1 :: kv_list(), Default :: term(), Value :: term(), KVList2 :: kv_list(). keypop(Key, KVList1, Default) -> case lists:keytake(Key, 1, KVList1) of {value, {Key, Value}, KVList2} -> {Value, KVList2}; false -> {Default, KVList1} end. %% @doc %% Converts the input data to a string. %% @end -spec to_string(Data :: term()) -> string() | no_return(). to_string(Data) when is_binary(Data) -> binary_to_list(Data); to_string(Data) when is_integer(Data) -> integer_to_list(Data); to_string(Data) when is_float(Data) -> lists:flatten(io_lib:format("~.1f", [Data])); to_string(Data) when is_atom(Data) -> atom_to_list(Data); to_string(Data) when is_list(Data) -> case io_lib:printable_list(Data) of true -> Data; false -> error({badarg, Data}) end; to_string(Data) -> error({badarg, Data}). %% @doc %% Reads the file info related to a tabfile saved previously. %% @end -spec read_tabfile(shards:filename()) -> term() | no_return(). read_tabfile(Filename) -> case file:read_file(Filename) of {ok, Binary} -> binary_to_term(Binary); Error -> throw(Error) end. %% @doc %% Writes to a file a content related to a table. %% @end -spec write_tabfile(shards:filename(), term()) -> ok | {error, term()}. write_tabfile(Filename, Content) -> file:write_file(Filename, term_to_binary(Content)).