File Coverage

lib/Data/SUID.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1 1     1   353 use strict;
  1         1  
  1         22  
2 1     1   3 use warnings;
  1         1  
  1         44  
3              
4             package Data::SUID;
5             our $VERSION = '2.0.3'; # VERSION
6 1     1   159 use Crypt::Random ( 'makerandom' );
  0            
  0            
7             use Exporter ();
8             use Net::Address::Ethernet ( 'get_address' );
9             use Math::BigInt try => 'GMP';
10             use MIME::Base64;
11             use Readonly;
12             use namespace::clean;
13             use overload '""' => 'hex';
14              
15             our @ISA = ( 'Exporter' );
16             our @EXPORT_OK = ( 'suid' );
17             our %EXPORT_TAGS = ( all => \@EXPORT_OK, ALL => \@EXPORT_OK );
18              
19             sub hex
20             {
21             my ( $self ) = @_;
22             $self = &new unless ref( $self );
23             return $$self;
24             }
25              
26             sub dec
27             {
28             my ( $self ) = @_;
29             $self = &new unless ref( $self );
30             return Math::BigInt->new( '0x' . $$self );
31             }
32              
33             sub uuencode
34             {
35             use bytes;
36             my ( $self ) = @_;
37             $self = &new unless ref( $self );
38             return pack( 'u', pack( 'H*', $$self ) );
39             }
40              
41             sub binary
42             {
43             use bytes;
44             my ( $self ) = @_;
45             $self = &new unless ref( $self );
46             return pack( 'H*', $$self );
47             }
48              
49             sub base64
50             {
51             use bytes;
52             my ( $self ) = @_;
53             $self = &new unless ref( $self );
54             return encode_base64( pack( 'H*', $$self ), '');
55             }
56              
57             sub suid { __PACKAGE__->new( @_ ) }
58              
59             sub new
60             {
61             my ( $class ) = @_;
62             $class = ref( $class ) || __PACKAGE__;
63             my $host = &_machine_ident;
64             my $count = &_count;
65             my $time = sprintf('%08x', time);
66             my $pid = sprintf('%05x', $$);
67             Readonly my $id => $time . $host . $pid . $count;
68             return bless( \$id, $class );
69             }
70              
71             {
72             my @ident;
73             my $ident;
74              
75             sub _machine_ident
76             {
77             my ($class, @bytes) = @_;
78             @ident = map 0 + ( $_ || 0 ), @bytes[ 0, 1, 3 ]
79             if @_;
80             @ident = +( map 0 + ( $_ || 0 ), get_address() )[ 3, 4, 5 ]
81             unless @ident;
82             $ident = sprintf( '%02x%02x%02x', @ident )
83             unless $ident;
84             return wantarray ? @ident : $ident;
85             }
86             }
87              
88             {
89             my $count_width = 20;
90             my $count_mask = 2 ** $count_width - 1;
91             my $count_format = '%0' . int( $count_width / 4 ) . 'x';
92             my $count = undef;
93              
94             sub _reset_count
95             {
96             my ( $class, $value ) = @_;
97             $count = $count_mask & ( 0 + abs( $value ) )
98             if defined $value;
99             unless ( defined $count ) {
100             $count = makerandom(
101             Strength => 1,
102             Uniform => 1,
103             Size => $count_width
104             );
105             }
106             return $class;
107             }
108              
109             sub _count
110             {
111             &_reset_count unless defined $count;
112             my $result = sprintf( $count_format, $count );
113             $count = $count_mask & ( 1 + $count );
114             return $result;
115             }
116             }
117              
118             1;
119              
120             =pod
121              
122             =encoding utf-8
123              
124             =head1 NAME
125              
126             Data::SUID - Generates sequential unique ids
127              
128             =head1 VERSION
129              
130             version 2.0.3
131              
132             =head1 SYNOPSIS
133              
134             use Data::SUID 'suid'; # Or use ':all' tag
135             use Data::Dumper;
136              
137             $Data::Dumper::Indent = 0;
138             $Data::Dumper::Terse = 1;
139              
140             my $suid = suid(); # Old school, or ...
141             my $suid = Data::SUID->new(); # Do it OOP style
142              
143             print $suid->dec # 26574773684474770905501261996
144             print $suid->hex # 55de233819d51b1a8a67e0ac
145             print $suid->uuencode # ,5=XC.!G5&QJ*9^"L
146             print $suid->base64 # Vyyx3wAAAAElgAAB
147             print $suid->binary # 12 bytes of unreadable gibberish
148             print $suid # 55de233819d51b1a8a67e0ac
149              
150             # Use the hex, dec, uuencode and binary methods as fire-and-forget
151             # constructors, if you prefer:
152              
153             my $suid_hex = suid->hex; # If you just want the goodies
154              
155             =head1 DESCRIPTION
156              
157             Use this package to generate 12-byte sequential unique ids modeled upon
158             Mongo's BSON ObjectId. Unlike traditional GUIDs, these are somewhat more
159             index-friendly and reasonably suited for use as primary keys within database
160             tables. They are guaranteed to have a high level of uniqueness, given that
161             they contain a timestamp, a host identifier and an incremented sequence
162             number.
163              
164             =head1 METHODS
165              
166             =head2 new
167              
168             $suid = Data::SUID->new();
169              
170             Generates a new SUID object.
171              
172             =head2 hex
173              
174             $string = $suid->hex();
175             $string = Data::SUID->hex();
176             $string = suid->hex();
177            
178             Returns the SUID value as a 24-character hexadecimal string.
179              
180             $string = "$suid";
181              
182             The SUID object's stringification operation has been overloaded to give this
183             value, too.
184              
185             =head2 dec
186              
187             $string = $suid->dec();
188             $string = Data::SUID->dec();
189             $string = suid->dec();
190              
191             Returns the SUID value as a big integer.
192              
193             =head2 uuencode
194              
195             $string = $suid->uuencode();
196             $string = Data::SUID->uuencode();
197             $string = suid->uuencode();
198              
199             Returns the SUID value as a UUENCODED string.
200              
201             =head2 binary
202              
203             $binstr = $suid->binary();
204             $binstr = Data::SUID->binary();
205             $binstr = suid->binary();
206              
207             Returns the SUID value as 12 bytes of binary data.
208              
209             =head2 base64
210              
211             $base64 = $suid->base64();
212             $base64 = Data::SUID->base64();
213             $base64 = suid->base64();
214              
215             Returns the SUID value as a 16-byte Base64 encoded string.
216              
217             =head1 EXPORTED FUNCTIONS
218              
219             =head2 suid
220              
221             my $suid = suid();
222              
223             Generates a new SUID object.
224              
225             =pod
226              
227             =head1 REPOSITORY
228              
229             =over 2
230              
231             =item * L
232              
233             =item * L
234              
235             =back
236              
237             =head1 BUG REPORTS
238              
239             Please report any bugs to L
240              
241             =head1 AUTHOR
242              
243             Iain Campbell
244              
245             =head1 COPYRIGHT AND LICENCE
246              
247             Copyright (C) 2014-2016 by Iain Campbell
248              
249             This library is free software; you can redistribute it and/or modify
250             it under the same terms as Perl itself.
251              
252             =cut