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