Current section

Files

Jump to
riak examples exploriak deps riakc src riakc_counter.erl
Raw

examples/exploriak/deps/riakc/src/riakc_counter.erl

%% -------------------------------------------------------------------
%%
%% riakc_counter: Eventually-consistent counter type
%%
%% Copyright (c) 2013 Basho Technologies, Inc. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
%% @doc Encapsulates a counter data-type. Counters are integers that
%% can be incremented or decremented. Like the other
%% eventually-consistent types, the original fetched value is
%% unmodified by increments. Instead, increments are captured for
%% later application in Riak.
-module(riakc_counter).
-behaviour(riakc_datatype).
-ifdef(EQC).
-include_lib("eqc/include/eqc.hrl").
-compile(export_all).
-endif.
%% Callbacks
-export([new/0, new/1, new/2,
value/1,
to_op/1,
is_type/1,
type/0]).
%% Operations
-export([increment/1, increment/2,
decrement/1, decrement/2]).
-record(counter, {
value = 0 :: integer(),
increment = undefined :: undefined | integer()
}).
-export_type([counter/0, counter_op/0]).
-opaque counter() :: #counter{}.
-type counter_op() :: {increment, integer()}.
%% @doc Creates a new counter type with a value of 0.
-spec new() -> counter().
new() ->
#counter{}.
%% @doc Creates a new counter type with the passed context. It's
%% ignored, but we need this constructor for new nested (in maps)
%% objects on the fly
-spec new(riakc_datatype:context()) -> counter().
new(_Context) ->
#counter{}.
%% @doc Creates a new counter type with the passed integer and
%% context.
-spec new(integer(), riakc_datatype:context()) -> counter().
new(Value, _Context) when is_integer(Value) ->
#counter{value=Value}.
%% @doc Gets the original value of the counter.
-spec value(counter()) -> integer().
value(#counter{value=Value}) ->
Value.
%% @doc Increments the counter by 1.
-spec increment(counter()) -> counter().
increment(Counter) ->
increment(1, Counter).
%% @doc Increments the counter by the passed amount.
-spec increment(integer(), counter()) -> counter().
increment(Amount, #counter{increment=undefined}=Counter) when is_integer(Amount) ->
Counter#counter{increment=Amount};
increment(Amount, #counter{increment=Incr}=Counter) when is_integer(Amount) ->
Counter#counter{increment=Incr+Amount}.
%% @doc Decrements the counter by 1.
-spec decrement(counter()) -> counter().
decrement(Counter) ->
increment(-1, Counter).
%% @doc Decrements the counter by the passed amount.
-spec decrement(integer(), counter()) -> counter().
decrement(Amount, Counter) ->
increment(-Amount, Counter).
%% @doc Extracts the changes to this counter as an operation.
-spec to_op(counter()) -> riakc_datatype:update(counter_op()).
to_op(#counter{increment=undefined}) ->
undefined;
to_op(#counter{increment=Incr}) ->
{type(), {increment, Incr}, undefined}.
%% @doc Determines whether the passed term is a counter container.
-spec is_type(term()) -> boolean().
is_type(T) ->
is_record(T, counter).
%% @doc Returns the symbolic name of this container.
-spec type() -> atom().
type() -> counter.
-ifdef(EQC).
gen_type() ->
?LET(Count, int(), new(Count, undefined)).
gen_op() ->
{elements([increment, decrement]),
weighted_default({1, []},
{5, [?SUCHTHAT(X, int(), X /= 0)]})}.
-endif.