1 %%%----------------------------------------------------------------------------
2 %%% Equivalent to stdlib's orddict, but with a pretty (IMO), uniform interface.
3 %%%----------------------------------------------------------------------------
6 -behavior(hope_gen_dictionary).
25 , validate_unique_presence/2 % Assume default optional parameter(s)
26 , validate_unique_presence/3 % Specify optional parameter(s)
33 -type presence_error(A) ::
35 | {keys_duplicated , [A]}
36 | {keys_unsupported , [A]}
40 %% ============================================================================
42 %% ============================================================================
49 -spec get(t(K, V), K) ->
52 case lists:keyfind(K, 1, T)
57 -spec get(t(K, V), K, V) ->
61 hope_option:get(Vopt, Default).
63 -spec set(t(K, V), K, V) ->
66 lists:keystore(K, 1, T, {K, V}).
68 -spec update(t(K, V), K, fun((hope_option:t(V)) -> V)) ->
73 % TODO: Eliminate the 2nd lookup.
76 -spec pop(t(K, V), K) ->
77 {hope_option:t(V), t(K, V)}.
79 case lists:keytake(K, 1, T1)
80 of {value, {K, V}, T2} -> {{some, V}, T2}
81 ; false -> {none , T1}
84 -spec iter(t(K, V), fun((K, V) -> ok)) ->
90 -spec map(t(K, V), fun((K, V) -> V)) ->
93 F2 = fun ({K, _}=X) -> {K, apply_map(F1, X)} end,
96 -spec filter(t(K, V), fun((K, V) -> boolean())) ->
102 -spec fold(t(K, V), fun((K, V, Acc) -> Acc), Acc) ->
104 fold(T, F1, Accumulator) ->
105 F2 = fun ({K, V}, Acc) -> F1(K, V, Acc) end,
106 lists:foldl(F2, Accumulator, T).
108 -spec to_kv_list(t(K, V)) ->
113 -spec of_kv_list([{K, V}]) ->
116 % TODO: Decide if validation is to be done here. Do so if yes.
119 -spec validate_unique_presence(t(K, _V), [K]) ->
120 hope_result:t(ok, [presence_error(K)]).
121 validate_unique_presence(T, KeysRequired) ->
123 validate_unique_presence(T, KeysRequired, KeysOptional).
125 -spec validate_unique_presence(t(K, _V), [K], [K]) ->
126 hope_result:t(ok, [presence_error(K)]).
127 validate_unique_presence(T, KeysRequired, KeysOptional) ->
128 KeysSupported = KeysRequired ++ KeysOptional,
129 KeysGiven = [K || {K, _V} <- T],
130 KeysGivenUnique = lists:usort(KeysGiven),
131 KeysDups = lists:usort(KeysGiven -- KeysGivenUnique),
132 KeysMissing = KeysRequired -- KeysGivenUnique,
133 KeysUnsupported = KeysGivenUnique -- KeysSupported,
134 case {KeysDups, KeysMissing, KeysUnsupported}
137 ; {Dups, Missing, Unsupported} ->
141 ; [_|_] -> [{keys_duplicated, Dups}]
146 ; [_|_] -> [{keys_missing, Missing}]
151 ; [_|_] -> [{keys_unsupported, Unsupported}]
153 Errors = ErrorDups ++ ErrorMissing ++ ErrorUnsupported,
158 %% ============================================================================
160 %% ============================================================================
164 when F :: fun(( K, V1 ) -> V2)
165 , G :: fun(({K, V1}) -> V2)
168 fun (X) -> apply_map(F, X) end.
170 -spec apply_map(fun((K, V1) -> V2), {K, V1}) ->
172 apply_map(F, {K, V}) ->