File Coverage

blib/lib/Types/Serialiser.pm
Criterion Covered Total %
statement 18 26 69.2
branch 6 6 100.0
condition n/a
subroutine 12 16 75.0
pod 8 9 88.8
total 44 57 77.1


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