ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Types-Serialiser/Serialiser.pm
(Generate patch)

Comparing Types-Serialiser/Serialiser.pm (file contents):
Revision 1.2 by root, Sun Oct 27 20:01:08 2013 UTC vs.
Revision 1.10 by root, Tue Dec 1 01:47:20 2020 UTC

15 15
16=cut 16=cut
17 17
18package Types::Serialiser; 18package Types::Serialiser;
19 19
20use common::sense; # required to suppress annoying warnings
21
20our $VERSION = 0.01; 22our $VERSION = '1.01';
21 23
22=head1 SIMPLE SCALAR CONSTANTS 24=head1 SIMPLE SCALAR CONSTANTS
23 25
24Simple scalar constants are values that are overloaded to act like simple 26Simple scalar constants are values that are overloaded to act like simple
25Perl values, but have (class) type to differentiate them from normal Perl 27Perl values, but have (class) type to differentiate them from normal Perl
26scalars. This is necessary because these have different representations in 28scalars. This is necessary because these have different representations in
27the serialisation formats. 29the serialisation formats.
28 30
31In the following, functions with zero or one arguments have a prototype of
32C<()> and C<($)>, respectively, so act as constants and unary operators.
33
29=head2 BOOLEANS (Types::Serialiser::Boolean class) 34=head2 BOOLEANS (Types::Serialiser::Boolean class)
30 35
31This type has only two instances, true and false. A natural representation 36This type has only two instances, true and false. A natural representation
32for these in Perl is C<1> and C<0>, but serialisation formats need to be 37for these in Perl is C<1> and C<0>, but serialisation formats need to be
33able to differentiate between them and mere numbers. 38able to differentiate between them and mere numbers.
49the number C<0>. It is up to you whether you use the variable form 54the number C<0>. It is up to you whether you use the variable form
50(C<$Types::Serialiser::false>) or the constant form (C<Types::Serialiser::false>). 55(C<$Types::Serialiser::false>) or the constant form (C<Types::Serialiser::false>).
51 56
52The constant is represented as a reference to a scalar containing C<0> - 57The constant is represented as a reference to a scalar containing C<0> -
53implementations are allowed to directly test for this. 58implementations are allowed to directly test for this.
59
60=item Types::Serialiser::as_bool $value
61
62Converts a Perl scalar into a boolean, which is useful syntactic
63sugar. Strictly equivalent to:
64
65 $value ? $Types::Serialiser::true : $Types::Serialiser::false
54 66
55=item $is_bool = Types::Serialiser::is_bool $value 67=item $is_bool = Types::Serialiser::is_bool $value
56 68
57Returns true iff the C<$value> is either C<$Types::Serialiser::true> or 69Returns true iff the C<$value> is either C<$Types::Serialiser::true> or
58C<$Types::Serialiser::false>. 70C<$Types::Serialiser::false>.
95 107
96=back 108=back
97 109
98=cut 110=cut
99 111
112BEGIN {
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 *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+" => sub { ${$_[0]} },
127 "++" => sub { $_[0] = ${$_[0]} + 1 },
128 "--" => sub { $_[0] = ${$_[0]} - 1 },
129 fallback => 1;
130
131 @Types::Serialiser::Boolean::ISA = Types::Serialiser::BooleanBase::;
132}
133
100our $true = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: }; 134our $true = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: };
101our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: }; 135our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: };
102our $error = do { bless \(my $dummy ), Types::Serialiser::Error:: }; 136our $error = do { bless \(my $dummy ), Types::Serialiser::Error:: };
103 137
104sub true () { $true } 138sub true () { $true }
105sub false () { $false } 139sub false () { $false }
106sub error () { $error } 140sub error () { $error }
141
142sub as_bool($) { $_[0] ? $true : $false }
107 143
108sub is_bool ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: } 144sub is_bool ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
109sub is_true ($) { $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: } 145sub is_true ($) { $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
110sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: } 146sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
111sub is_error ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Error:: } 147sub is_error ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Error:: }
112
113package Types::Serialiser::Boolean;
114
115use overload
116 "0+" => sub { ${$_[0]} },
117 "++" => sub { $_[0] = ${$_[0]} + 1 },
118 "--" => sub { $_[0] = ${$_[0]} - 1 },
119 fallback => 1;
120 148
121package Types::Serialiser::Error; 149package Types::Serialiser::Error;
122 150
123sub error { 151sub error {
124 require Carp; 152 require Carp;
139see if it's C<1> (true), C<0> (false) or C<undef> (error). 167see if it's C<1> (true), C<0> (false) or C<undef> (error).
140 168
141While it is possible to use an isa test, directly comparing stash pointers 169While it is possible to use an isa test, directly comparing stash pointers
142is faster and guaranteed to work. 170is faster and guaranteed to work.
143 171
172For historical reasons, the C<Types::Serialiser::Boolean> stash is
173just an alias for C<JSON::PP::Boolean>. When printed, the classname
174with usually be C<JSON::PP::Boolean>, but isa tests and stash pointer
175comparison will normally work correctly (i.e. Types::Serialiser::true ISA
176JSON::PP::Boolean, but also ISA Types::Serialiser::Boolean).
177
178=head1 A GENERIC OBJECT SERIALIATION PROTOCOL
179
180This section explains the object serialisation protocol used by
181L<CBOR::XS>. It is meant to be generic enough to support any kind of
182generic object serialiser.
183
184This protocol is called "the Types::Serialiser object serialisation
185protocol".
186
187=head2 ENCODING
188
189When the encoder encounters an object that it cannot otherwise encode (for
190example, L<CBOR::XS> can encode a few special types itself, and will first
191attempt to use the special C<TO_CBOR> serialisation protocol), it will
192look up the C<FREEZE> method on the object.
193
194Note that the C<FREEZE> method will normally be called I<during> encoding,
195and I<MUST NOT> change the data structure that is being encoded in any
196way, or it might cause memory corruption or worse.
197
198If it exists, it will call it with two arguments: the object to serialise,
199and a constant string that indicates the name of the data model. For
200example L<CBOR::XS> uses C<CBOR>, and the L<JSON> and L<JSON::XS> modules
201(or any other JSON serialiser), would use C<JSON> as second argument.
202
203The C<FREEZE> method can then return zero or more values to identify the
204object instance. The serialiser is then supposed to encode the class name
205and all of these return values (which must be encodable in the format)
206using the relevant form for Perl objects. In CBOR for example, there is a
207registered tag number for encoded perl objects.
208
209The values that C<FREEZE> returns must be serialisable with the serialiser
210that calls it. Therefore, it is recommended to use simple types such as
211strings and numbers, and maybe array references and hashes (basically, the
212JSON data model). You can always use a more complex format for a specific
213data model by checking the second argument, the data model.
214
215The "data model" is not the same as the "data format" - the data model
216indicates what types and kinds of return values can be returned from
217C<FREEZE>. For example, in C<CBOR> it is permissible to return tagged CBOR
218values, while JSON does not support these at all, so C<JSON> would be a
219valid (but too limited) data model name for C<CBOR::XS>. similarly, a
220serialising format that supports more or less the same data model as JSON
221could use C<JSON> as data model without losing anything.
222
223=head2 DECODING
224
225When the decoder then encounters such an encoded perl object, it should
226look up the C<THAW> method on the stored classname, and invoke it with the
227classname, the constant string to identify the data model/data format, and
228all the return values returned by C<FREEZE>.
229
230=head2 EXAMPLES
231
232See the C<OBJECT SERIALISATION> section in the L<CBOR::XS> manpage for
233more details, an example implementation, and code examples.
234
235Here is an example C<FREEZE>/C<THAW> 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
144=head1 BUGS 249=head1 BUGS
145 250
146The use of L<overload> makes this module much heavier than it should be 251The use of L<overload> makes this module much heavier than it should be
147(on my system, this module: 4kB RSS, overload: 260kB RSS). 252(on my system, this module: 4kB RSS, overload: 260kB RSS).
148 253

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines