ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Types-Serialiser/Serialiser.pm
Revision: 1.4
Committed: Mon Oct 28 15:28:44 2013 UTC (10 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-0_02
Changes since 1.3: +19 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.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 root 1.4 use common::sense; # required to suppress annoying warnings
21    
22     our $VERSION = 0.02;
23 root 1.1
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<Types::Serialiser::true>).
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<Types::Serialiser::false>).
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<Types::Serialiser::true> 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<error>. 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<undef>
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 root 1.4 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     *Types::Serialiser::Boolean:: = *JSON::PP::Boolean::;
107     }
108    
109 root 1.1 our $true = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: };
110     our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: };
111     our $error = do { bless \(my $dummy ), Types::Serialiser::Error:: };
112    
113     sub true () { $true }
114     sub false () { $false }
115     sub error () { $error }
116    
117     sub is_bool ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
118     sub is_true ($) { $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
119     sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
120     sub is_error ($) { UNIVERSAL::isa $_[0], Types::Serialiser::Error:: }
121    
122 root 1.4 package Types::Serialiser::BooleanBase;
123 root 1.1
124     use overload
125     "0+" => sub { ${$_[0]} },
126     "++" => sub { $_[0] = ${$_[0]} + 1 },
127     "--" => sub { $_[0] = ${$_[0]} - 1 },
128     fallback => 1;
129    
130 root 1.4 @Types::Serialiser::Boolean::ISA = Types::Serialiser::BooleanBase::;
131    
132 root 1.1 package Types::Serialiser::Error;
133    
134     sub error {
135     require Carp;
136 root 1.2 Carp::croak ("caught attempt to use the Types::Serialiser::error value");
137 root 1.1 };
138    
139     use overload
140     "0+" => \&error,
141     "++" => \&error,
142     "--" => \&error,
143     fallback => 1;
144    
145 root 1.2 =head1 NOTES FOR XS USERS
146    
147     The recommended way to detect whether a scalar is one of these objects
148     is to check whether the stash is the C<Types::Serialiser::Boolean> or
149     C<Types::Serialiser::Error> stash, and then follow the scalar reference to
150     see if it's C<1> (true), C<0> (false) or C<undef> (error).
151    
152     While it is possible to use an isa test, directly comparing stash pointers
153     is faster and guaranteed to work.
154    
155 root 1.4 For historical reasons, the C<Types::Serialiser::Boolean> stash is
156     just an alias for C<JSON::PP::Boolean>. When printed, the classname
157     withh usually be C<JSON::PP::Boolean>, but isa tests and stash pointer
158     comparison will normally work correctly (i.e. Types::Serialiser::true ISA
159     JSON::PP::Boolean, but also ISA Types::Serialiser::Boolean).
160    
161 root 1.3 =head1 A GENERIC OBJECT SERIALIATION PROTOCOL
162    
163     This section explains the object serialisation protocol used by
164     L<CBOR::XS>. It is meant to be generic enough to support any kind of
165     generic object serialiser.
166    
167     This protocol is called "the Types::Serialiser object serialisation
168     protocol".
169    
170     =head2 ENCODING
171    
172     When the encoder encounters an object that it cannot otherwise encode (for
173     example, L<CBOR::XS> can encode a few special types itself, and will first
174     attempt to use the special C<TO_CBOR> serialisation protocol), it will
175     look up the C<FREEZE> method on the object.
176    
177     If it exists, it will call it with two arguments: the object to
178     serialise, and a constant string that indicates the name of the
179     serialisationformat. For example L<CBOR::XS> uses C<CBOR>, and L<JSON> and
180     L<JSON::XS> (or any other JSON serialiser), would use C<JSON> as second
181     argument.
182    
183     The C<FREEZE> method can then return zero or more values to identify the
184     object instance. The serialiser is then supposed to encode the class name
185     and all of these return values (which must be encodable in the format)
186     using the relevant form for perl objects. In CBOR for example, there is a
187     registered tag number for encoded perl objects.
188    
189     =head2 DECODING
190    
191     When the decoder then encounters such an encoded perl object, it should
192     look up the C<THAW> method on the stored classname, and invoke it with the
193     classname, the constant string to identify the format, and all the return
194     values returned by C<FREEZE>.
195    
196     =head2 EXAMPLES
197    
198     See the C<OBJECT SERIALISATION> section in the L<CBOR::XS> manpage for
199     more details, an example implementation, and code examples.
200    
201     Here is an example C<FREEZE>/C<THAW> method pair:
202    
203     sub My::Object::FREEZE {
204     my ($self, $serialiser) = @_;
205    
206     ($self->{type}, $self->{id}, $self->{variant})
207     }
208    
209     sub My::Object::THAW {
210     my ($class, $serialiser, $type, $id, $variant) = @_;
211    
212     $class-<new (type => $type, id => $id, variant => $variant)
213     }
214    
215 root 1.1 =head1 BUGS
216    
217     The use of L<overload> makes this module much heavier than it should be
218     (on my system, this module: 4kB RSS, overload: 260kB RSS).
219    
220     =head1 SEE ALSO
221    
222     Currently, L<JSON::XS> and L<CBOR::XS> use these types.
223    
224     =head1 AUTHOR
225    
226     Marc Lehmann <schmorp@schmorp.de>
227     http://home.schmorp.de/
228    
229     =cut
230    
231     1
232