%%% Copyright (c) 2018, Klarna AB %%% %%% Licensed 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. -module(kpro_varint). -compile({inline, [enc_zigzag/1]}). -export([ encode/1 , decode/1 ]). -export([ encode_unsigned/1 , decode_unsigned/1 ]). -define(MAX_BITS, 63). %% @doc Decode varint. -spec decode(binary()) -> {integer(), binary()}. decode(Bin) -> dec_zigzag(dec_varint(Bin)). %% @doc Encode varint. -spec encode(kpro:int64()) -> iodata(). encode(Int) -> enc_varint(enc_zigzag(Int)). %% @doc Encode unsigned varint. -spec encode_unsigned(non_neg_integer()) -> iodata(). encode_unsigned(Int) when Int >= 0 -> enc_varint(Int). %% @doc Decode unsigned varint. -spec decode_unsigned(binary()) -> {non_neg_integer(), binary()}. decode_unsigned(Bin) -> dec_varint(Bin). -spec enc_zigzag(integer()) -> non_neg_integer(). enc_zigzag(Int) -> true = (Int >= -(1 bsl ?MAX_BITS)), true = (Int < ((1 bsl ?MAX_BITS) - 1)), (Int bsl 1) bxor (Int bsr ?MAX_BITS). -spec enc_varint(non_neg_integer()) -> iodata(). enc_varint(I) when I =< 127 -> [I]; enc_varint(I) -> [128 + I band 127 | enc_varint(I bsr 7)]. -spec dec_zigzag({integer(), binary()} | integer()) -> {integer(), binary()} | integer(). dec_zigzag({Int, TailBin}) -> {(Int bsr 1) bxor -(Int band 1), TailBin}. -spec dec_varint(binary()) -> {integer(), binary()}. dec_varint(Bin) -> dec_varint(Bin, 0, 0). -spec dec_varint(binary(), integer(), integer()) -> {integer(), binary()}. dec_varint(Bin, Acc, AccBits) -> true = (AccBits =< ?MAX_BITS), %% assert <> = Bin, NewAcc = (Value bsl AccBits) bor Acc, case Tag =:= 0 of true -> {NewAcc, Tail}; false -> dec_varint(Tail, NewAcc, AccBits + 7) end. %%%_* Emacs ==================================================================== %%% Local Variables: %%% allout-layout: t %%% erlang-indent-level: 2 %%% End: