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.4 by root, Mon Oct 28 15:28:44 2013 UTC vs.
Revision 1.9 by root, Sat Nov 30 18:33:51 2013 UTC

17 17
18package Types::Serialiser; 18package Types::Serialiser;
19 19
20use common::sense; # required to suppress annoying warnings 20use common::sense; # required to suppress annoying warnings
21 21
22our $VERSION = 0.02; 22our $VERSION = '1.0';
23 23
24=head1 SIMPLE SCALAR CONSTANTS 24=head1 SIMPLE SCALAR CONSTANTS
25 25
26Simple scalar constants are values that are overloaded to act like simple 26Simple scalar constants are values that are overloaded to act like simple
27Perl values, but have (class) type to differentiate them from normal Perl 27Perl values, but have (class) type to differentiate them from normal Perl
101 101
102BEGIN { 102BEGIN {
103 # for historical reasons, and to avoid extra dependencies in JSON::PP, 103 # for historical reasons, and to avoid extra dependencies in JSON::PP,
104 # we alias *Types::Serialiser::Boolean with JSON::PP::Boolean. 104 # we alias *Types::Serialiser::Boolean with JSON::PP::Boolean.
105 package JSON::PP::Boolean; 105 package JSON::PP::Boolean;
106
106 *Types::Serialiser::Boolean:: = *JSON::PP::Boolean::; 107 *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 "0+" => sub { ${$_[0]} },
117 "++" => sub { $_[0] = ${$_[0]} + 1 },
118 "--" => sub { $_[0] = ${$_[0]} - 1 },
119 fallback => 1;
120
121 @Types::Serialiser::Boolean::ISA = Types::Serialiser::BooleanBase::;
107} 122}
108 123
109our $true = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: }; 124our $true = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: };
110our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: }; 125our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: };
111our $error = do { bless \(my $dummy ), Types::Serialiser::Error:: }; 126our $error = do { bless \(my $dummy ), Types::Serialiser::Error:: };
116 131
117sub is_bool ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: } 132sub is_bool ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
118sub is_true ($) { $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: } 133sub is_true ($) { $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
119sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: } 134sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
120sub is_error ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Error:: } 135sub is_error ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Error:: }
121
122package Types::Serialiser::BooleanBase;
123
124use overload
125 "0+" => sub { ${$_[0]} },
126 "++" => sub { $_[0] = ${$_[0]} + 1 },
127 "--" => sub { $_[0] = ${$_[0]} - 1 },
128 fallback => 1;
129
130@Types::Serialiser::Boolean::ISA = Types::Serialiser::BooleanBase::;
131 136
132package Types::Serialiser::Error; 137package Types::Serialiser::Error;
133 138
134sub error { 139sub error {
135 require Carp; 140 require Carp;
152While it is possible to use an isa test, directly comparing stash pointers 157While it is possible to use an isa test, directly comparing stash pointers
153is faster and guaranteed to work. 158is faster and guaranteed to work.
154 159
155For historical reasons, the C<Types::Serialiser::Boolean> stash is 160For historical reasons, the C<Types::Serialiser::Boolean> stash is
156just an alias for C<JSON::PP::Boolean>. When printed, the classname 161just an alias for C<JSON::PP::Boolean>. When printed, the classname
157withh usually be C<JSON::PP::Boolean>, but isa tests and stash pointer 162with usually be C<JSON::PP::Boolean>, but isa tests and stash pointer
158comparison will normally work correctly (i.e. Types::Serialiser::true ISA 163comparison will normally work correctly (i.e. Types::Serialiser::true ISA
159JSON::PP::Boolean, but also ISA Types::Serialiser::Boolean). 164JSON::PP::Boolean, but also ISA Types::Serialiser::Boolean).
160 165
161=head1 A GENERIC OBJECT SERIALIATION PROTOCOL 166=head1 A GENERIC OBJECT SERIALIATION PROTOCOL
162 167
172When the encoder encounters an object that it cannot otherwise encode (for 177When the encoder encounters an object that it cannot otherwise encode (for
173example, L<CBOR::XS> can encode a few special types itself, and will first 178example, L<CBOR::XS> can encode a few special types itself, and will first
174attempt to use the special C<TO_CBOR> serialisation protocol), it will 179attempt to use the special C<TO_CBOR> serialisation protocol), it will
175look up the C<FREEZE> method on the object. 180look up the C<FREEZE> method on the object.
176 181
182Note that the C<FREEZE> method will normally be called I<during> encoding,
183and I<MUST NOT> change the data structure that is being encoded in any
184way, or it might cause memory corruption or worse.
185
177If it exists, it will call it with two arguments: the object to 186If it exists, it will call it with two arguments: the object to serialise,
178serialise, and a constant string that indicates the name of the 187and a constant string that indicates the name of the data model. For
179serialisationformat. For example L<CBOR::XS> uses C<CBOR>, and L<JSON> and 188example L<CBOR::XS> uses C<CBOR>, and the L<JSON> and L<JSON::XS> modules
180L<JSON::XS> (or any other JSON serialiser), would use C<JSON> as second 189(or any other JSON serialiser), would use C<JSON> as second argument.
181argument.
182 190
183The C<FREEZE> method can then return zero or more values to identify the 191The C<FREEZE> method can then return zero or more values to identify the
184object instance. The serialiser is then supposed to encode the class name 192object instance. The serialiser is then supposed to encode the class name
185and all of these return values (which must be encodable in the format) 193and all of these return values (which must be encodable in the format)
186using the relevant form for perl objects. In CBOR for example, there is a 194using the relevant form for Perl objects. In CBOR for example, there is a
187registered tag number for encoded perl objects. 195registered tag number for encoded perl objects.
196
197The values that C<FREEZE> returns must be serialisable with the serialiser
198that calls it. Therefore, it is recommended to use simple types such as
199strings and numbers, and maybe array references and hashes (basically, the
200JSON data model). You can always use a more complex format for a specific
201data model by checking the second argument, the data model.
202
203The "data model" is not the same as the "data format" - the data model
204indicates what types and kinds of return values can be returned from
205C<FREEZE>. For example, in C<CBOR> it is permissible to return tagged CBOR
206values, while JSON does not support these at all, so C<JSON> would be a
207valid (but too limited) data model name for C<CBOR::XS>. similarly, a
208serialising format that supports more or less the same data model as JSON
209could use C<JSON> as data model without losing anything.
188 210
189=head2 DECODING 211=head2 DECODING
190 212
191When the decoder then encounters such an encoded perl object, it should 213When the decoder then encounters such an encoded perl object, it should
192look up the C<THAW> method on the stored classname, and invoke it with the 214look up the C<THAW> method on the stored classname, and invoke it with the
193classname, the constant string to identify the format, and all the return 215classname, the constant string to identify the data model/data format, and
194values returned by C<FREEZE>. 216all the return values returned by C<FREEZE>.
195 217
196=head2 EXAMPLES 218=head2 EXAMPLES
197 219
198See the C<OBJECT SERIALISATION> section in the L<CBOR::XS> manpage for 220See the C<OBJECT SERIALISATION> section in the L<CBOR::XS> manpage for
199more details, an example implementation, and code examples. 221more details, an example implementation, and code examples.
200 222
201Here is an example C<FREEZE>/C<THAW> method pair: 223Here is an example C<FREEZE>/C<THAW> method pair:
202 224
203 sub My::Object::FREEZE { 225 sub My::Object::FREEZE {
204 my ($self, $serialiser) = @_; 226 my ($self, $model) = @_;
205 227
206 ($self->{type}, $self->{id}, $self->{variant}) 228 ($self->{type}, $self->{id}, $self->{variant})
207 } 229 }
208 230
209 sub My::Object::THAW { 231 sub My::Object::THAW {
210 my ($class, $serialiser, $type, $id, $variant) = @_; 232 my ($class, $model, $type, $id, $variant) = @_;
211 233
212 $class-<new (type => $type, id => $id, variant => $variant) 234 $class->new (type => $type, id => $id, variant => $variant)
213 } 235 }
214 236
215=head1 BUGS 237=head1 BUGS
216 238
217The use of L<overload> makes this module much heavier than it should be 239The use of L<overload> makes this module much heavier than it should be

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines