Current section
Files
Jump to
Current section
Files
src/optic_array.erl
%%%-------------------------------------------------------------------
%%% @doc
%%% A set of optics specific to arrays.
%%% @end
%%%-------------------------------------------------------------------
-module(optic_array).
%% API
-export([all/0,
all/1,
nth/1,
nth/2]).
%%%===================================================================
%%% API
%%%===================================================================
%% @see all/1
-spec all() -> optic:optic().
all() ->
all(#{}).
%% @doc
%% Focus on all values of an array.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_array:all()], array:from_list([1,2,3])).
%% {ok,[1,2,3]}
%% '''
%% @end
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec all(Options) -> optic:optic() when
Options :: optic:variations().
all(Options) ->
Fold =
fun (Fun, Acc, Array) ->
case is_array(Array) of
true ->
{ok, array:foldl(fun (_Index, Elem, InnerAcc) ->
Fun(Elem, InnerAcc)
end, Acc, Array)};
false ->
{error, undefined}
end
end,
MapFold =
fun (Fun, Acc, Array) ->
case is_array(Array) of
true ->
{ok, array:foldl(fun (Index, Elem, {InnerArray, InnerAcc}) ->
{NewElem, NewAcc} = Fun(Elem, InnerAcc),
{array:set(Index, NewElem, InnerArray), NewAcc}
end,
{Array, Acc},
Array)};
false ->
{error, undefined}
end
end,
New =
fun (_Data, Template) ->
array:new([{default, Template}])
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).
%% @see nth/2
-spec nth(N) -> optic:optic() when
N :: pos_integer().
nth(N) ->
nth(N, #{}).
%% @doc
%% Focus on the nth value of an array. Like lists, but unlike the
%% standard array operations, indexing begins at 1.
%%
%% Example:
%%
%% ```
%% > optic:get([optic_array:nth(1)], array:from_list([1,2,3])).
%% {ok,[1]}
%% '''
%% @end
%% @param N The index of the array value to focus on.
%% @param Options Common optic options.
%% @returns An opaque optic record.
-spec nth(N, Options) -> optic:optic() when
N :: pos_integer(),
Options :: optic:variations().
nth(N, Options) when N >= 1 ->
Index = N - 1,
Fold =
fun (Fun, Acc, Array) ->
case is_array(Array) andalso valid_index(Index, Array) of
true ->
Elem = array:get(Index, Array),
{ok, Fun(Elem, Acc)};
false ->
{error, undefined}
end
end,
MapFold =
fun (Fun, Acc, Array) ->
case is_array(Array) andalso valid_index(Index, Array) of
true ->
Elem = array:get(Index, Array),
{NewElem, NewAcc} = Fun(Elem, Acc),
{ok, {array:set(Index, NewElem, Array), NewAcc}};
false ->
{error, undefined}
end
end,
New =
fun (Data, Template) ->
case is_array(Data) of
true ->
array:resize(N, Data);
false ->
array:new(N, [{default, Template}])
end
end,
Optic = optic:new(MapFold, Fold),
optic:variations(Optic, Options, New).
%%%===================================================================
%%% Internal Functions
%%%===================================================================
is_array(Unknown) ->
try array:size(Unknown) of
_ ->
true
catch
error:badarg ->
false
end.
valid_index(Index, Array) when Index >= 0 ->
case array:is_fix(Array) of
true ->
Index < array:size(Array);
false ->
true
end.