File Coverage

blib/lib/Types/Serialiser.pm
Criterion Covered Total %
statement 19 25 76.0
branch 4 4 100.0
condition n/a
subroutine 12 15 80.0
pod 7 8 87.5
total 42 52 80.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Types::Serialiser - simple data types for common serialisation formats
4              
5             =encoding utf-8
6              
7             =head1 SYNOPSIS
8              
9             =head1 DESCRIPTION
10              
11             This module provides some extra datatypes that are used by common
12             serialisation formats such as JSON or CBOR. The idea is to have a
13             repository of simple/small constants and containers that can be shared by
14             different implementations so they become interoperable between each other.
15              
16             =cut
17              
18             package Types::Serialiser;
19              
20 2     2   5393 use common::sense; # required to suppress annoying warnings
  2         21  
  2         11  
21              
22             our $VERSION = '1.0';
23              
24             =head1 SIMPLE SCALAR CONSTANTS
25              
26             Simple scalar constants are values that are overloaded to act like simple
27             Perl values, but have (class) type to differentiate them from normal Perl
28             scalars. This is necessary because these have different representations in
29             the serialisation formats.
30              
31             =head2 BOOLEANS (Types::Serialiser::Boolean class)
32              
33             This type has only two instances, true and false. A natural representation
34             for these in Perl is C<1> and C<0>, but serialisation formats need to be
35             able to differentiate between them and mere numbers.
36              
37             =over 4
38              
39             =item $Types::Serialiser::true, Types::Serialiser::true
40              
41             This value represents the "true" value. In most contexts is acts like
42             the number C<1>. It is up to you whether you use the variable form
43             (C<$Types::Serialiser::true>) or the constant form (C).
44              
45             The constant is represented as a reference to a scalar containing C<1> -
46             implementations are allowed to directly test for this.
47              
48             =item $Types::Serialiser::false, Types::Serialiser::false
49              
50             This value represents the "false" value. In most contexts is acts like
51             the number C<0>. It is up to you whether you use the variable form
52             (C<$Types::Serialiser::false>) or the constant form (C).
53              
54             The constant is represented as a reference to a scalar containing C<0> -
55             implementations are allowed to directly test for this.
56              
57             =item $is_bool = Types::Serialiser::is_bool $value
58              
59             Returns true iff the C<$value> is either C<$Types::Serialiser::true> or
60             C<$Types::Serialiser::false>.
61              
62             For example, you could differentiate between a perl true value and a
63             C by using this:
64              
65             $value && Types::Serialiser::is_bool $value
66              
67             =item $is_true = Types::Serialiser::is_true $value
68              
69             Returns true iff C<$value> is C<$Types::Serialiser::true>.
70              
71             =item $is_false = Types::Serialiser::is_false $value
72              
73             Returns false iff C<$value> is C<$Types::Serialiser::false>.
74              
75             =back
76              
77             =head2 ERROR (Types::Serialiser::Error class)
78              
79             This class has only a single instance, C. It is used to signal
80             an encoding or decoding error. In CBOR for example, and object that
81             couldn't be encoded will be represented by a CBOR undefined value, which
82             is represented by the error value in Perl.
83              
84             =over 4
85              
86             =item $Types::Serialiser::error, Types::Serialiser::error
87              
88             This value represents the "error" value. Accessing values of this type
89             will throw an exception.
90              
91             The constant is represented as a reference to a scalar containing C
92             - implementations are allowed to directly test for this.
93              
94             =item $is_error = Types::Serialiser::is_error $value
95              
96             Returns false iff C<$value> is C<$Types::Serialiser::error>.
97              
98             =back
99              
100             =cut
101              
102             BEGIN {
103             # for historical reasons, and to avoid extra dependencies in JSON::PP,
104             # we alias *Types::Serialiser::Boolean with JSON::PP::Boolean.
105             package JSON::PP::Boolean;
106              
107 2     2   778 *Types::Serialiser::Boolean:: = *JSON::PP::Boolean::;
108             }
109              
110             {
111             # this must done before blessing to work around bugs
112             # in perl < 5.18 (it seems to be fixed in 5.18).
113             package Types::Serialiser::BooleanBase;
114              
115             use overload
116 19     19   92 "0+" => sub { ${$_[0]} },
  19         70  
117 0     0   0 "++" => sub { $_[0] = ${$_[0]} + 1 },
  0         0  
118 0     0   0 "--" => sub { $_[0] = ${$_[0]} - 1 },
  0         0  
119 2     2   12728 fallback => 1;
  2         2803  
  2         29  
120              
121             @Types::Serialiser::Boolean::ISA = Types::Serialiser::BooleanBase::;
122             }
123              
124             our $true = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: };
125             our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: };
126             our $error = do { bless \(my $dummy ), Types::Serialiser::Error:: };
127              
128 1     1 1 10 sub true () { $true }
129 1     1 1 42 sub false () { $false }
130 1     1 1 9 sub error () { $error }
131              
132 2     2 1 30 sub is_bool ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
133 2 100   2 1 83 sub is_true ($) { $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
134 2 100   2 1 20 sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
135 1     1 1 10 sub is_error ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Error:: }
136              
137             package Types::Serialiser::Error;
138              
139             sub error {
140 0     0 0   require Carp;
141 0           Carp::croak ("caught attempt to use the Types::Serialiser::error value");
142             };
143              
144             use overload
145 2         10 "0+" => \&error,
146             "++" => \&error,
147             "--" => \&error,
148 2     2   1729 fallback => 1;
  2         4  
149              
150             =head1 NOTES FOR XS USERS
151              
152             The recommended way to detect whether a scalar is one of these objects
153             is to check whether the stash is the C or
154             C stash, and then follow the scalar reference to
155             see if it's C<1> (true), C<0> (false) or C (error).
156              
157             While it is possible to use an isa test, directly comparing stash pointers
158             is faster and guaranteed to work.
159              
160             For historical reasons, the C stash is
161             just an alias for C. When printed, the classname
162             with usually be C, but isa tests and stash pointer
163             comparison will normally work correctly (i.e. Types::Serialiser::true ISA
164             JSON::PP::Boolean, but also ISA Types::Serialiser::Boolean).
165              
166             =head1 A GENERIC OBJECT SERIALIATION PROTOCOL
167              
168             This section explains the object serialisation protocol used by
169             L. It is meant to be generic enough to support any kind of
170             generic object serialiser.
171              
172             This protocol is called "the Types::Serialiser object serialisation
173             protocol".
174              
175             =head2 ENCODING
176              
177             When the encoder encounters an object that it cannot otherwise encode (for
178             example, L can encode a few special types itself, and will first
179             attempt to use the special C serialisation protocol), it will
180             look up the C method on the object.
181              
182             Note that the C method will normally be called I encoding,
183             and I change the data structure that is being encoded in any
184             way, or it might cause memory corruption or worse.
185              
186             If it exists, it will call it with two arguments: the object to serialise,
187             and a constant string that indicates the name of the data model. For
188             example L uses C, and the L and L modules
189             (or any other JSON serialiser), would use C as second argument.
190              
191             The C method can then return zero or more values to identify the
192             object instance. The serialiser is then supposed to encode the class name
193             and all of these return values (which must be encodable in the format)
194             using the relevant form for Perl objects. In CBOR for example, there is a
195             registered tag number for encoded perl objects.
196              
197             The values that C returns must be serialisable with the serialiser
198             that calls it. Therefore, it is recommended to use simple types such as
199             strings and numbers, and maybe array references and hashes (basically, the
200             JSON data model). You can always use a more complex format for a specific
201             data model by checking the second argument, the data model.
202              
203             The "data model" is not the same as the "data format" - the data model
204             indicates what types and kinds of return values can be returned from
205             C. For example, in C it is permissible to return tagged CBOR
206             values, while JSON does not support these at all, so C would be a
207             valid (but too limited) data model name for C. similarly, a
208             serialising format that supports more or less the same data model as JSON
209             could use C as data model without losing anything.
210              
211             =head2 DECODING
212              
213             When the decoder then encounters such an encoded perl object, it should
214             look up the C method on the stored classname, and invoke it with the
215             classname, the constant string to identify the data model/data format, and
216             all the return values returned by C.
217              
218             =head2 EXAMPLES
219              
220             See the C section in the L manpage for
221             more details, an example implementation, and code examples.
222              
223             Here is an example C/C method pair:
224              
225             sub My::Object::FREEZE {
226             my ($self, $model) = @_;
227              
228             ($self->{type}, $self->{id}, $self->{variant})
229             }
230              
231             sub My::Object::THAW {
232             my ($class, $model, $type, $id, $variant) = @_;
233              
234             $class->new (type => $type, id => $id, variant => $variant)
235             }
236              
237             =head1 BUGS
238              
239             The use of L makes this module much heavier than it should be
240             (on my system, this module: 4kB RSS, overload: 260kB RSS).
241              
242             =head1 SEE ALSO
243              
244             Currently, L and L use these types.
245              
246             =head1 AUTHOR
247              
248             Marc Lehmann
249             http://home.schmorp.de/
250              
251             =cut
252              
253             1
254