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