File Coverage

lib/Data/Identifier/Util.pm
Criterion Covered Total %
statement 111 234 47.4
branch 74 166 44.5
condition 10 63 15.8
subroutine 14 17 82.3
pod 5 7 71.4
total 214 487 43.9


line stmt bran cond sub pod time code
1             # Copyright (c) 2023-2026 Philipp Schafft
2              
3             # licensed under Artistic License 2.0 (see LICENSE file)
4              
5             # ABSTRACT: format independent identifier object
6              
7              
8             package Data::Identifier::Util;
9              
10 2     2   231150 use v5.14;
  2         7  
11 2     2   10 use strict;
  2         3  
  2         46  
12 2     2   7 use warnings;
  2         4  
  2         90  
13              
14 2     2   7 use parent qw(Data::Identifier::Interface::Userdata Data::Identifier::Interface::Subobjects);
  2         3  
  2         13  
15              
16 2     2   103 use Carp;
  2         2  
  2         107  
17              
18 2     2   638 use Data::Identifier;
  2         6  
  2         10  
19 2     2   552 use Data::Identifier::Generate;
  2         4  
  2         1403  
20              
21             our $VERSION = v0.29;
22              
23             my $_DEFAULT_INSTANCE = __PACKAGE__->new;
24              
25             my %_4plus12_prefix = (
26             sni => (0<<15)|(0<<14),
27             sid => (0<<15)|(1<<14),
28             hdi => (1<<15)|(0<<14),
29             udi => (1<<15)|(1<<14),
30             );
31              
32             my $_logical = '5e80c7b7-215e-4154-b310-a5387045c336';
33              
34             my %_raes_to_raen = (
35             NONE => 0,
36             NOENT => 2,
37             NOSYS => 6,
38             NOTSUP => 7,
39             NOMEM => 12,
40             INVAL => 13,
41             FAULT => 18,
42             IO => 19,
43             NODATA => 25,
44             NOSPC => 38,
45             TYPEMM => 39,
46             RO => 45,
47             ILLSEQ => 56,
48             BADEXEC => 79,
49             BADFH => 83,
50             );
51             my %_logicals_to_sni = (
52             sni => 10,
53             sid => 115,
54             raen => 116,
55             chat0w => 118,
56             uuid => 119,
57             uri => 121,
58             asciicp => 122,
59             oid => 120,
60             wd => 123,
61             logical => 129,
62             false => 189,
63             true => 190,
64             );
65             my %_logicals_to_sid = (
66             asi => 1,
67             tagname => 3,
68             SEEK_SET => 34,
69             SEEK_CUR => 35,
70             SEEK_END => 36,
71             backwards => 43,
72             forwards => 44,
73             black => 61,
74             white => 62,
75             grey => 63,
76             red => 119,
77             green => 120,
78             blue => 121,
79             cyan => 122,
80             magenta => 123,
81             yellow => 124,
82             orange => 125,
83             gtin => 160,
84             left => 192,
85             right => 193,
86             up => 194,
87             down => 195,
88             north => 208,
89             east => 209,
90             south => 210,
91             west => 211,
92             );
93              
94             my %_wk = (
95             bunit_ns => {uuid => 'e8e9846a-37ec-42fd-8e89-d15f5467aa9c', displayname => 'unit-namespace'},
96             bunit_gen => {uuid => 'b1620795-b29a-4aea-ba46-371b187d0a4b', displayname => 'unit-generator'},
97             dunit_ns => {uuid => 'da8a7fe4-935c-4bf7-9bd1-aaf8fc39305b', displayname => 'derived-unit-namespace'},
98             dunit_gen => {uuid => 'c3446cff-672b-4247-b62c-755a295ee15f', displayname => 'derived-unit-generator'},
99             #x => {uuid => '', displayname => ''},
100             );
101              
102             foreach my $value (values %_wk) {
103             my $uuid = delete $value->{uuid};
104             $value = Data::Identifier->new(uuid => $uuid, %{$value})->register;
105             }
106              
107             my %_base_units = (
108             map {
109             $_->{id} = Data::Identifier::Generate->generic(
110             namespace => $_wk{bunit_ns},
111             generator => $_wk{bunit_gen},
112             style => 'name-based',
113             request => $_->{symbol},
114             displayname => $_->{name},
115             )->register;
116             $_->{symbol} => $_
117             } (
118             {name => 'second', symbol => 's', dimension => 'T', quantity => 'time', variable => [qw(t)]},
119             {name => 'metre', symbol => 'm', dimension => 'L', quantity => 'length', variable => [qw(l x r)]},
120             {name => 'kilogram', symbol => 'kg', dimension => 'M', quantity => 'mass', variable => [qw(m)]},
121             {name => 'ampere', symbol => 'A', dimension => 'I', quantity => 'electric current', variable => [qw(I i)]},
122             {name => 'kelvin', symbol => 'K', dimension => "\N{U+0398}", quantity => 'thermodynamic temperature', variable => [qw(T)]},
123             {name => 'mole', symbol => 'mol', dimension => 'N', quantity => 'amount of substance', variable => [qw(n)]},
124             {name => 'candela', symbol => 'cd', dimension => 'J', quantity => 'luminous intensity', variable => [qw(Iv)]},
125             )
126             );
127              
128             my %_number_units = map { $_ => Data::Identifier::Generate->integer($_)->register } (2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73); # primes
129              
130             my %_composite_unit_elements = (
131             Hz => {s => -1},
132             N => {s => -2, m => 1, kg => 1},
133             Pa => {s => -2, m => -1, kg => 1},
134             J => {s => -2, m => 2, kg => 1},
135             W => {s => -3, m => 2, kg => 1},
136             C => {s => 1, A => 1},
137             V => {s => -3, m => 2, kg => 1, A => -1},
138             F => {s => 4, m => -2, kg => -1, A => 2},
139             "\N{U+03A9}" => {s => -3, m => 2, kg => 1, A => -2},
140             "\N{U+2126}" => {s => -3, m => 2, kg => 1, A => -2}, # alias
141             ohm => {s => -3, m => 2, kg => 1, A => -2}, # alias
142             S => {s => 3, m => -2, kg => -1, A => 2},
143             Wb => {s => -2, m => 2, kg => 1, A => -1},
144             T => {s => -2, kg => 1, A => -1},
145             H => {s => -2, m => 2, kg => 1, A => -2},
146             kat => {s => -1, mol => 1},
147             10 => {2 => 1, 5 => 1},
148             12 => {2 => 2, 3 => 1},
149             24 => {2 => 3, 3 => 1},
150             28 => {2 => 2, 7 => 1},
151             30 => {2 => 1, 3 => 1, 5 => 1},
152             60 => {2 => 2, 3 => 1, 5 => 1},
153             365 => { 5 => 1, 73 => 1},
154             366 => {2 => 1, 3 => 1, 61 => 1},
155             3600 => {2 => 4, 3 => 2, 5 => 2},
156             86400 => {2 => 7, 3 => 3, 5 => 2},
157             );
158              
159             my %_component_to_name = (
160             # Units:
161             (map {$_base_units{$_}{id}->uuid => $_} keys %_base_units),
162             # Numbers:
163             (map {$_number_units{$_}->uuid => $_} keys %_number_units),
164             );
165              
166             my %_si_prefix = (
167             quetta => 30, Q => 30,
168             ronna => 27, R => 27,
169             yotta => 24, Y => 24,
170             zetta => 21, Z => 21,
171             exa => 18, E => 18,
172             peta => 15, P => 15,
173             tera => 12, T => 12,
174             giga => 9, G => 9,
175             mega => 6, M => 6,
176             kilo => 3, k => 3,
177             hecto => 2, h => 2,
178             deca => 1, da => 1,
179             deci => -1, d => -1,
180             centi => -2, c => -2,
181             milli => -3, m => -3,
182 2     2   1531 micro => -6, "\N{GREEK SMALL LETTER MU}" => -6,
  2         13183  
  2         10  
183             nano => -9, n => -9,
184             pico => -12, p => -12,
185             femto => -15, f => -15,
186             atto => -18, a => -18,
187             zepto => -21, z => -21,
188             yocto => -24, y => -24,
189             ronto => -27, r => -27,
190             quecto => -30, q => -30,
191             );
192              
193              
194             sub new {
195 3     3 1 489 my ($pkg, @opts) = @_;
196              
197 3 50       12 croak 'Stray options passed' if scalar @opts;
198              
199 3         10 return bless {}, $pkg;
200             }
201              
202              
203             sub pack {
204 9     9 1 2855 my ($self, $template, $identifier, @opts) = _normalise_args(@_);
205 9         16 my $pack_template;
206             my $v;
207              
208 9 50       15 croak 'Stray options passed' if scalar @opts;
209              
210 9   50     19 $template //= '';
211 9 50       10 $identifier = Data::Identifier->new(from => $identifier) unless eval {$identifier->isa('Data::Identifier')};
  9         29  
212              
213 9 100       57 if ($template =~ /^(sid|sni|hdi|udi)([1-9][0-9]*)$/) {
    50          
    100          
    100          
    50          
    0          
214 6         16 my $bits = int($2);
215              
216 6         21 $v = $identifier->as(Data::Identifier->new(wellknown => $1), no_defaults => 1);
217              
218 6 100       46 if ($bits == 8) {
    100          
    50          
219 2         4 $pack_template = 'C';
220             } elsif ($bits == 16) {
221 2         4 $pack_template = 'n';
222             } elsif ($bits == 32) {
223 2         4 $pack_template = 'N';
224             } else {
225 0         0 croak 'Invalid width: '.$bits;
226             }
227             } elsif ($template eq '4+12') {
228 0         0 my $prefix;
229              
230 0         0 foreach my $type (qw(sid sni hdi udi)) {
231 0         0 $v = $identifier->as(Data::Identifier->new(wellknown => $type), no_defaults => 1, default => undef);
232 0 0       0 if (defined $v) {
233 0 0 0     0 if ($v < 0 || $v > 0x0FFF) {
234 0         0 next;
235             }
236 0         0 $v |= $_4plus12_prefix{$type};
237 0         0 $pack_template = 'n';
238 0         0 last;
239             }
240             }
241             } elsif ($template eq 'uuid128') {
242 1         3 return pack('H*', $identifier->uuid(no_defaults => 1) =~ tr/-//dr);
243             } elsif ($template eq 'uuidhexdash') {
244 1         7 return $identifier->uuid(no_defaults => 1);
245             } elsif ($template eq 'uuidHEXDASH') {
246 1         4 return $identifier->uuid(no_defaults => 1) =~ tr/a-f/A-F/r;
247             } elsif ($template eq 'Data::Identifier') {
248 0         0 return $identifier;
249             }
250              
251 6 50 33     23 if (defined($v) && defined($pack_template)) {
252 6         9 my ($min, $max);
253              
254 6 100       20 if ($pack_template eq 'C') {
    100          
    50          
255 2         3 ($min, $max) = (0, 0xFF);
256             } elsif ($pack_template eq 'n') {
257 2         4 ($min, $max) = (0, 0xFFFF);
258             } elsif ($pack_template eq 'N') {
259 2         3 ($min, $max) = (0, 0xFFFF_FFFF);
260             }
261              
262 6 50 33     52 if ((defined($min) && $v < $min) || (defined($max) && $v > $max)) {
      33        
      33        
263 0         0 croak 'Identifier not in range for '.$template.': '.$v;
264             }
265              
266 6         53 return pack($pack_template, $v);
267             }
268              
269 0         0 croak 'Unknown template: '.$template;
270             }
271              
272              
273             sub unpack {
274 9     9 1 24 my ($self, $template, $data, @opts) = _normalise_args(@_);
275 9         14 my $pack_template;
276             my $type;
277              
278 9 50       19 croak 'Stray options passed' if scalar @opts;
279              
280 9 100       55 if ($template =~ /^(sid|sni|hdi|udi)([1-9][0-9]*)$/) {
    50          
    100          
    100          
    50          
    0          
281 6         14 my $bits = int($2);
282 6         10 $type = $1;
283              
284 6 100       17 if ($bits == 8) {
    100          
    50          
285 2         3 $pack_template = 'C';
286             } elsif ($bits == 16) {
287 2         21 $pack_template = 'n';
288             } elsif ($bits == 32) {
289 2         4 $pack_template = 'N';
290             } else {
291 0         0 croak 'Invalid width: '.$bits;
292             }
293             } elsif ($template eq '4+12') {
294 0         0 my $v;
295             my $prefix;
296              
297 0 0       0 croak 'Input has bad length, expected 2 bytes, got '.length($data) unless length($data) == 2;
298              
299 0         0 $v = unpack('n', $data);
300 0         0 $prefix = $v & 0xF000;
301 0         0 $v = $v & 0x0FFF;
302              
303 0         0 foreach my $key (keys %_4plus12_prefix) {
304 0 0       0 if ($prefix == $_4plus12_prefix{$key}) {
305 0         0 return Data::Identifier->new($key => $v);
306             }
307             }
308              
309 0         0 croak sprintf('Invalid/unknown prefix: 0x%04x', $prefix);
310             } elsif ($template eq 'uuid128') {
311 1 50       4 croak 'Input has bad length, expected 16 bytes, got '.length($data) unless length($data) == 16;
312 1         9 return Data::Identifier->new(uuid => join('-', unpack('H8H4H4H4H12', $data)));
313             } elsif ($template eq 'uuidhexdash') {
314 1         7 return Data::Identifier->new(uuid => $data);
315             } elsif ($template eq 'uuidHEXDASH') {
316 1         5 return Data::Identifier->new(uuid => $data);
317             } elsif ($template eq 'Data::Identifier') {
318             # We don't care too much here if it is actually a Data::Identifier or just any other supported type.
319             # Data::Identifier will do the right thing anyway.
320 0         0 return Data::Identifier->new(from => $data);
321             }
322              
323 6 50 33     19 if (defined($type) && defined($pack_template)) {
324 6         9 my $len = length($data);
325 6         6 my $exp;
326              
327 6 100       14 if ($pack_template eq 'C') {
    100          
    50          
328 2         2 $exp = 1;
329             } elsif ($pack_template eq 'n') {
330 2         4 $exp = 2;
331             } elsif ($pack_template eq 'N') {
332 2         3 $exp = 4;
333             }
334              
335 6 50       10 croak 'Input has bad length, expected '.$exp.' bytes, got '.$len unless $len == $exp;
336              
337 6         29 return Data::Identifier->new($type => unpack($pack_template, $data));
338             }
339              
340 0         0 croak 'Unknown template: '.$template;
341             }
342              
343              
344             sub parse_sirtx {
345 16     16 1 2820 my ($self, $data, @opts) = _normalise_args(@_);
346              
347 16 50       31 croak 'Stray options passed' if scalar @opts;
348              
349 16         27 $self->_load_well_known;
350              
351 16         53 $data =~ s/^\[(.+)\]$/$1/;
352              
353             # Experimental:
354 16 100       42 if (my ($d, $v) = $data =~ /^(\[.+?\]):(.+)$/) {
355 1         5 $d = $self->parse_sirtx($d);
356 1         4 $v =~ s/^\[(.+)\]$/$1/;
357 1         3 return Data::Identifier->new($d => $v);
358             }
359              
360 15 100       93 if ($data =~ /^'([0-9]*)$/) {
    50          
    100          
    100          
    50          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
    50          
361 2   50     11 my $num = int($1 || '0');
362 2         11 require Data::Identifier::Generate;
363 2         8 return Data::Identifier::Generate->integer($num);
364             } elsif ($data =~ /^\/([0-9]+)$/) {
365 0         0 return Data::Identifier->new('d73b6550-5309-46ad-acc9-865c9261065b' => int($1));
366             } elsif ($data =~ /^(sid|sni):([0-9]+)$/) {
367 4         17 return Data::Identifier->new($1 => int($2));
368             } elsif ($data =~ /^uuid:([0-9a-fA-F-]+)$/) {
369 2         7 return Data::Identifier->new(uuid => $1);
370             } elsif ($data =~ /^wd:([QPL][1-9][0-9]*)$/) {
371 0         0 return Data::Identifier->new(wd => $1);
372             } elsif ($data =~ /^~([0-9]+)$/) {
373 0         0 return Data::Identifier->new(hdi => int($1));
374             } elsif ($data =~ /^raen:([0-9]+)$/) {
375 1         5 return Data::Identifier->new('2bffc55d-7380-454e-bd53-c5acd525d692' => int($1));
376             } elsif ($data =~ /^chat0w:([0-9]+)$/) {
377 1         5 return Data::Identifier->new('2c7e15ed-aa2f-4e2f-9a1d-64df0c85875a' => int($1));
378             } elsif ($data =~ /^asciicp:([0-9]+)$/) {
379 0         0 require Data::Identifier::Generate;
380 0         0 return Data::Identifier::Generate->unicode_character(ascii => int($1));
381             } elsif ($data =~ /^raes:(.+)/) {
382 1 50       5 if (defined(my $raen = $_raes_to_raen{$1})) {
383 1         4 return Data::Identifier->new('2bffc55d-7380-454e-bd53-c5acd525d692' => $raen);
384             }
385             } elsif (defined $_logicals_to_sni{$data}) {
386 2         8 return Data::Identifier->new(sni => $_logicals_to_sni{$data});
387             } elsif (defined $_logicals_to_sid{$data}) {
388 0         0 return Data::Identifier->new(sid => $_logicals_to_sid{$data});
389             } elsif ($data =~ /^logical:(.+)$/) {
390 2         6 $data = $1;
391 2 50       4 if (defined $_logicals_to_sni{$data}) {
    0          
392 2         9 return Data::Identifier->new(sni => $_logicals_to_sni{$data});
393             } elsif (defined $_logicals_to_sid{$data}) {
394 0         0 return Data::Identifier->new(sid => $_logicals_to_sid{$data});
395             }
396             }
397              
398 0         0 croak 'Unsupported/invalid SIRTX identifier';
399             }
400              
401              
402             sub render_sirtx {
403 0     0 1 0 my ($self, $identifier, @opts) = _normalise_args(@_);
404 0         0 state $map = [
405             [sid => Data::Identifier->new(wellknown => 'sid')->register],
406             [sni => Data::Identifier->new(wellknown => 'sni')->register],
407             [wd => Data::Identifier->new(wellknown => 'wd')->register],
408             ['/' => Data::Identifier->new(uuid => 'd73b6550-5309-46ad-acc9-865c9261065b')->register],
409             [raen => Data::Identifier->new(uuid => '2bffc55d-7380-454e-bd53-c5acd525d692')->register],
410             [chat0w => Data::Identifier->new(uuid => '2c7e15ed-aa2f-4e2f-9a1d-64df0c85875a')->register],
411             ['~' => Data::Identifier->new(wellknown => 'hdi')->register],
412             ];
413              
414 0 0       0 croak 'Stray options passed' if scalar @opts;
415              
416 0         0 $identifier = Data::Identifier->new(from => $identifier);
417              
418 0 0 0     0 if (defined(my Data::Identifier $generator = $identifier->generator(default => undef)) && defined(my $req = $identifier->request(default => undef))) {
419 0 0 0     0 if ($generator->eq('53863a15-68d4-448d-bd69-a9b19289a191')) {
    0          
420 0         0 return sprintf('\'%u', $req);
421             } elsif ($generator->eq('d74f8c35-bcb8-465c-9a77-01010e8ed25c') && $req =~ /^[Uu]\+([0-9a-fA-F]{4,6})$/) {
422 0         0 my $cp = hex $1;
423 0 0       0 if ($cp < 0x80) {
424 0         0 return sprintf('asciicp:%u', $cp);
425             }
426             }
427             }
428              
429 0         0 foreach my $ent (@{$map}) {
  0         0  
430 0   0     0 my $v = $identifier->as($ent->[1], no_defaults => 1, default => undef) // next;
431 0 0       0 $v = sprintf($ent->[0] =~ /^[a-z]/ ? '%s:%s' : '%s%s', $ent->[0], $v);
432 0 0       0 $v = '['.$v.']' if $v =~ /-/;
433 0         0 return $v;
434             }
435              
436             # Fallback:
437 0         0 return sprintf('[uuid:%s]', $identifier->uuid);
438             }
439              
440             # Too experimental for listing in public API.
441             # TODO: Get this on track for the public API!
442             sub parse_unit_request {
443 0     0 0 0 my ($self, $template, $request, %opts) = _normalise_args(@_);
444 0   0     0 my $exponentas = delete($opts{exponentas}) // 'int';
445 0         0 my @res;
446              
447 0 0       0 croak 'Stray options passed' if scalar keys %opts;
448              
449 0 0       0 if ($template eq 'request') {
450 0         0 foreach my $subreq (split(/--/, $request)) {
451 0         0 my ($uuid, $neg, $exp_mul) = $subreq =~ /^([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})~(-?)([0-9])\z/;
452 0         0 my $exp;
453              
454             #printf("%-42s -> <%s> <%1s> <%s>\n", $subreq, $uuid, $neg, $exp_mul);
455              
456 0 0       0 if ($exponentas eq 'int') {
457 0         0 $exp = int($exp_mul);
458 0 0       0 $exp = -$exp if $neg eq '-';
459             } else {
460 0         0 croak 'Invalid exponentas: '.$exponentas;
461             }
462              
463 0         0 push(@res, {
464             component => Data::Identifier->new(uuid => $uuid),
465             exponent => $exp,
466             });
467             }
468             } else {
469 0         0 croak 'Unknown template: '.$template;
470             }
471              
472 0         0 return \@res;
473             }
474              
475             # Too experimental for listing in public API.
476             # TODO: Get this on track for the public API!
477             sub render_unit_request {
478 0     0 0 0 my ($pkg, $template, $request, %opts) = _normalise_args(@_);
479 0         0 my $displayname = delete $opts{displayname};
480 0         0 my $input;
481             my %took;
482              
483 0 0       0 croak 'Stray options passed' if scalar keys %opts;
484              
485 0 0       0 if (ref($request) eq 'ARRAY') {
486 0   0     0 $request = {map {($_component_to_name{$_->{component}->uuid} // croak 'Unknown base unit: '.$_->{component}->uuid) => $_->{exponent}} @{$request}};
  0         0  
  0         0  
487             }
488              
489 0 0       0 if (defined(my $prefix = delete($request->{prefix}))) {
490 0   0     0 $prefix = $_si_prefix{$prefix} // croak 'Bad prefix: '.$prefix;
491 0   0     0 $request->{10} //= 0;
492 0         0 $request->{10} += $prefix;
493             }
494              
495 0         0 foreach my $key (keys(%_composite_unit_elements)) {
496 0         0 my $n = $_composite_unit_elements{$key};
497 0   0     0 my $mul = delete($request->{$key}) // 0;
498 0 0       0 croak 'Bad exponent: '.$mul if $mul != int($mul);
499 0         0 $mul = int($mul);
500 0 0       0 next if $mul == 0;
501 0         0 foreach my $prime_element (keys %{$n}) {
  0         0  
502 0   0     0 $request->{$prime_element} //= 0;
503 0         0 $request->{$prime_element} += $n->{$prime_element} * $mul;
504             }
505             }
506              
507 0         0 foreach my $key (keys(%_base_units), keys(%_number_units)) {
508 0   0     0 my $mul = delete($request->{$key}) // 0;
509 0 0       0 croak 'Bad exponent: '.$mul if $mul != int($mul);
510 0         0 $mul = int($mul);
511 0 0       0 $took{$key} = $mul if $mul != 0;
512             }
513              
514             {
515 0         0 my @keys = keys %{$request};
  0         0  
  0         0  
516 0 0       0 croak 'Bad extra units: '.join(', ', @keys) if scalar @keys;
517             }
518              
519 0 0       0 unless (scalar(grep {!defined $_number_units{$_}} keys %took)) {
  0         0  
520 0         0 my $i = 1;
521              
522 0         0 foreach my $key (keys %took) {
523 0         0 $i *= $key ** $took{$key};
524             }
525              
526 0 0       0 if ($i == int($i)) {
527 0         0 return $pkg->pack($template => Data::Identifier::Generate->integer($i));
528             }
529 0         0 croak 'Invalid numeric only request';
530             }
531              
532             # Rename from units to UUIDs as keys.
533 0         0 foreach my $key (keys %took) {
534 0   0     0 my $uuid = ($_number_units{$key} // $_base_units{$key}{id})->uuid;
535 0         0 $took{$uuid} = delete $took{$key};
536             }
537              
538 0 0       0 if (scalar(keys %took) == 1) {
539 0         0 my ($mul) = values %took;
540 0 0       0 if ($mul == 1) {
541 0         0 my ($uuid) = keys %took;
542 0         0 return $pkg->pack($template => Data::Identifier->new(uuid => $uuid));
543             }
544             }
545              
546 0         0 $input = join('--', map{$_.'~'.$took{$_}} sort keys %took);
  0         0  
547              
548 0 0       0 if ($template eq 'request') {
549 0         0 return $input;
550             }
551              
552             $opts{namespace} //= $_wk{dunit_ns},
553             $opts{generator} //= $_wk{dunit_gen},
554 0   0     0 $opts{input} = $input;
      0        
555 0         0 $opts{request} = $input;
556 0         0 $opts{displayname} = $displayname;
557              
558 0         0 return $pkg->pack($template => Data::Identifier::Generate->generic(%opts));
559             }
560              
561             # ---- Private helpers ----
562              
563             sub _normalise_args {
564 34     34   79 my (@args) = @_;
565              
566 34 50       65 if (scalar(@args)) {
567 34 50 33     94 if (ref($args[0]) && eval {$args[0]->isa(__PACKAGE__)}) {
  34 0       155  
568             # no-op
569             } elsif ($args[0] eq __PACKAGE__) {
570 0         0 $args[0] = $_DEFAULT_INSTANCE;
571             } else {
572 0         0 unshift(@args, $_DEFAULT_INSTANCE);
573             }
574              
575 34         112 return @args;
576             }
577              
578 0         0 return ($_DEFAULT_INSTANCE);
579             }
580              
581             sub _load_well_known {
582 16     16   20 state $done = do {
583 1         3 my %meta = (
584             sni => \%_logicals_to_sni,
585             sid => \%_logicals_to_sid,
586             );
587              
588 1         4 foreach my $type (keys %meta) {
589 2         2 my $hash = $meta{$type};
590              
591 2         3 foreach my $key (keys %{$hash}) {
  2         11  
592 38         83 my $id = Data::Identifier->new($type => $hash->{$key});
593              
594 38 100       61 next unless defined $id->uuid(no_defaults => 1, default => undef);
595              
596 14   50     27 $id->{id_cache} //= {};
597 14   33     42 $id->{id_cache}->{$_logical} //= $key;
598              
599 14         22 $id->register;
600             }
601             }
602             };
603             }
604              
605             1;
606              
607             __END__