File Coverage

blib/lib/Web3/Tiny/RLP.pm
Criterion Covered Total %
statement 34 34 100.0
branch 12 14 85.7
condition 4 6 66.6
subroutine 7 7 100.0
pod 0 2 0.0
total 57 63 90.4


line stmt bran cond sub pod time code
1             package Web3::Tiny::RLP;
2              
3 3     3   79787 use strict;
  3         6  
  3         109  
4 3     3   16 use warnings;
  3         5  
  3         120  
5 3     3   12 use Exporter 'import';
  3         4  
  3         101  
6 3     3   1360 use Math::BigInt;
  3         34989  
  3         18  
7              
8             our $VERSION = '0.01';
9             our @EXPORT_OK = qw(rlp_encode int_to_bytes);
10              
11             # int_to_bytes($n) -> minimal big-endian byte string (raw), with 0 => ''
12             # $n may be a plain non-negative integer, a decimal/hex string, or a
13             # Math::BigInt object.
14             sub int_to_bytes {
15 20     20 0 3874 my ($n) = @_;
16 20 50 33     146 my $bi = ref($n) && $n->isa('Math::BigInt') ? $n->copy : Math::BigInt->new("$n");
17 20 100       2530 return '' if $bi->is_zero;
18              
19 19         405 my $hex = $bi->as_hex;
20 19         2319 $hex =~ s/^0x//;
21 19 100       66 $hex = '0' . $hex if length($hex) % 2;
22 19         158 return pack('H*', $hex);
23             }
24              
25             # rlp_encode($item) -> raw RLP-encoded byte string
26             #
27             # $item is either:
28             # - a plain scalar: treated as a raw byte string (NOT a decimal number --
29             # convert integers with int_to_bytes() first)
30             # - an array ref: treated as an RLP list, encoded recursively
31             sub rlp_encode {
32 50     50 0 150300 my ($item) = @_;
33              
34 50 100       249 if (ref($item) eq 'ARRAY') {
35 13         30 my $payload = join '', map { rlp_encode($_) } @$item;
  36         79  
36 13         38 return _with_length_prefix($payload, 0xc0, 0xf7);
37             }
38              
39 37 50       81 my $str = defined($item) ? $item : '';
40 37 100 100     115 if (length($str) == 1 && ord($str) <= 0x7f) {
41 8         30 return $str;
42             }
43 29         62 return _with_length_prefix($str, 0x80, 0xb7);
44             }
45              
46             sub _with_length_prefix {
47 42     42   86 my ($payload, $short_base, $long_base) = @_;
48 42         65 my $len = length($payload);
49              
50 42 100       101 if ($len <= 55) {
51 40         182 return chr($short_base + $len) . $payload;
52             }
53              
54 2         12 my $len_bytes = int_to_bytes($len);
55 2         33 return chr($long_base + length($len_bytes)) . $len_bytes . $payload;
56             }
57              
58             1;
59              
60             __END__