]> gitweb.factorcode.org Git - factor.git/blob - basis/serialize/serialize.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / basis / serialize / serialize.factor
1 ! Copyright (C) 2006 Adam Langley and Chris Double.
2 ! Adam Langley was the original author of this work.
3 !
4 ! Chris Double modified it to fix bugs and get it working
5 ! correctly under the latest versions of Factor.
6 !
7 ! See http://factorcode.org/license.txt for BSD license.
8 !
9 USING: namespaces sequences kernel math io math.functions
10 io.binary strings classes words sbufs classes.tuple arrays
11 vectors byte-arrays quotations hashtables assocs help.syntax
12 help.markup splitting io.streams.byte-array io.encodings.string
13 io.encodings.utf8 io.encodings.binary combinators accessors
14 locals prettyprint compiler.units sequences.private
15 classes.tuple.private ;
16 IN: serialize
17
18 GENERIC: (serialize) ( obj -- )
19
20 <PRIVATE
21
22 ! Variable holding a assoc of objects already serialized
23 SYMBOL: serialized
24
25 TUPLE: id obj ;
26
27 C: <id> id
28
29 M: id hashcode* obj>> hashcode* ;
30
31 M: id equal? over id? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
32
33 : add-object ( obj -- )
34     #! Add an object to the sequence of already serialized
35     #! objects.
36     serialized get [ assoc-size swap <id> ] keep set-at ;
37
38 : object-id ( obj -- id )
39     #! Return the id of an already serialized object 
40     <id> serialized get at ;
41
42 ! Numbers are serialized as follows:
43 ! 0 => B{ 0 }
44 ! 1<=x<=126 => B{ x | 0x80 }
45 ! x>127 => B{ length(x) x[0] x[1] ... }
46 ! x>2^1024 => B{ 0xff length(x) x[0] x[1] ... }
47 ! The last case is needed because a very large number would
48 ! otherwise be confused with a small number.
49 : serialize-cell ( n -- )
50     dup zero? [ drop 0 write1 ] [
51         dup HEX: 7e <= [
52             HEX: 80 bitor write1
53         ] [
54             dup log2 8 /i 1+ 
55             dup HEX: 7f >= [
56                 HEX: ff write1
57                 dup serialize-cell
58             ] [
59                 dup write1
60             ] if
61             >be write
62         ] if
63     ] if ;
64
65 : deserialize-cell ( -- n )
66     read1 {
67         { [ dup HEX: ff = ] [ drop deserialize-cell read be> ] }
68         { [ dup HEX: 80 >= ] [ HEX: 80 bitxor ] }
69         [ read be> ]
70     } cond ;
71
72 : serialize-shared ( obj quot -- )
73     [
74         dup object-id
75         [ CHAR: o write1 serialize-cell drop ]
76     ] dip if* ; inline
77
78 M: f (serialize) ( obj -- )
79     drop CHAR: n write1 ;
80
81 M: integer (serialize) ( obj -- )
82     dup zero? [
83         drop CHAR: z write1
84     ] [
85         dup 0 < [ neg CHAR: m ] [ CHAR: p ] if write1
86         serialize-cell
87     ] if ;
88
89 M: float (serialize) ( obj -- )
90     CHAR: F write1
91     double>bits serialize-cell ;
92
93 M: complex (serialize) ( obj -- )
94     CHAR: c write1
95     [ real-part (serialize) ]
96     [ imaginary-part (serialize) ] bi ;
97
98 M: ratio (serialize) ( obj -- )
99     CHAR: r write1
100     [ numerator (serialize) ]
101     [ denominator (serialize) ] bi ;
102
103 : serialize-seq ( obj code -- )
104     [
105         write1
106         [ add-object ]
107         [ length serialize-cell ]
108         [ [ (serialize) ] each ] tri
109     ] curry serialize-shared ;
110
111 M: tuple (serialize) ( obj -- )
112     [
113         CHAR: T write1
114         [ class (serialize) ]
115         [ add-object ]
116         [ tuple>array rest (serialize) ]
117         tri
118     ] serialize-shared ;
119
120 M: array (serialize) ( obj -- )
121     CHAR: a serialize-seq ;
122
123 M: quotation (serialize) ( obj -- )
124     [
125         CHAR: q write1
126         [ >array (serialize) ] [ add-object ] bi
127     ] serialize-shared ;
128
129 M: hashtable (serialize) ( obj -- )
130     [
131         CHAR: h write1
132         [ add-object ] [ >alist (serialize) ] bi
133     ] serialize-shared ;
134
135 M: byte-array (serialize) ( obj -- )
136     [
137         CHAR: A write1
138         [ add-object ]
139         [ length serialize-cell ]
140         [ write ] tri
141     ] serialize-shared ;
142
143 M: string (serialize) ( obj -- )
144     [
145         CHAR: s write1
146         [ add-object ]
147         [
148             utf8 encode
149             [ length serialize-cell ]
150             [ write ] bi
151         ] bi
152     ] serialize-shared ;
153
154 : serialize-true ( word -- )
155     drop CHAR: t write1 ;
156
157 : serialize-gensym ( word -- )
158     [
159         CHAR: G write1
160         [ add-object ]
161         [ def>> (serialize) ]
162         [ props>> (serialize) ]
163         tri
164     ] serialize-shared ;
165
166 : serialize-word ( word -- )
167     CHAR: w write1
168     [ name>> (serialize) ]
169     [ vocabulary>> (serialize) ]
170     bi ;
171
172 M: word (serialize) ( obj -- )
173     {
174         { [ dup t eq? ] [ serialize-true ] }
175         { [ dup vocabulary>> not ] [ serialize-gensym ] }
176         [ serialize-word ]
177     } cond ;
178
179 M: wrapper (serialize) ( obj -- )
180     CHAR: W write1
181     wrapped>> (serialize) ;
182
183 DEFER: (deserialize) ( -- obj )
184
185 SYMBOL: deserialized
186
187 : intern-object ( obj -- )
188     deserialized get push ;
189
190 : deserialize-false ( -- f )
191     f ;
192
193 : deserialize-true ( -- f )
194     t ;
195
196 : deserialize-positive-integer ( -- number )
197     deserialize-cell ;
198
199 : deserialize-negative-integer ( -- number )
200     deserialize-positive-integer neg ;
201
202 : deserialize-zero ( -- number )
203     0 ;
204
205 : deserialize-float ( -- float )
206     deserialize-cell bits>double ;
207
208 : deserialize-ratio ( -- ratio )
209     (deserialize) (deserialize) / ;
210
211 : deserialize-complex ( -- complex )
212     (deserialize) (deserialize) rect> ;
213
214 : (deserialize-string) ( -- string )
215     deserialize-cell read utf8 decode ;
216
217 : deserialize-string ( -- string )
218     (deserialize-string) dup intern-object ;
219
220 : deserialize-word ( -- word )
221     (deserialize) (deserialize) 2dup lookup
222     dup [ 2nip ] [
223         drop
224         2array unparse "Unknown word: " prepend throw
225     ] if ;
226
227 : deserialize-gensym ( -- word )
228     gensym {
229         [ intern-object ]
230         [ (deserialize) define ]
231         [ (deserialize) >>props drop ]
232         [ ]
233     } cleave ;
234
235 : deserialize-wrapper ( -- wrapper )
236     (deserialize) <wrapper> ;
237
238 :: (deserialize-seq) ( exemplar quot -- seq )
239     deserialize-cell exemplar new-sequence
240     [ intern-object ]
241     [ dup [ drop quot call ] change-each ] bi ; inline
242
243 : deserialize-array ( -- array )
244     { } [ (deserialize) ] (deserialize-seq) ;
245
246 : deserialize-quotation ( -- array )
247     (deserialize) >quotation dup intern-object ;
248
249 : deserialize-byte-array ( -- byte-array )
250     B{ } [ read1 ] (deserialize-seq) ;
251
252 : deserialize-hashtable ( -- hashtable )
253     H{ } clone
254     [ intern-object ]
255     [ (deserialize) update ]
256     [ ] tri ;
257
258 : copy-seq-to-tuple ( seq tuple -- )
259     [ dup length ] dip [ set-array-nth ] curry 2each ;
260
261 : deserialize-tuple ( -- array )
262     #! Ugly because we have to intern the tuple before reading
263     #! slots
264     (deserialize) new
265     [ intern-object ]
266     [
267         [ (deserialize) ]
268         [ [ copy-seq-to-tuple ] keep ] bi*
269     ] bi ;
270
271 : deserialize-unknown ( -- object )
272     deserialize-cell deserialized get nth ;
273
274 : deserialize* ( -- object ? )
275     read1 [
276         {
277             { CHAR: A [ deserialize-byte-array ] }
278             { CHAR: F [ deserialize-float ] }
279             { CHAR: T [ deserialize-tuple ] }
280             { CHAR: W [ deserialize-wrapper ] }
281             { CHAR: a [ deserialize-array ] }
282             { CHAR: c [ deserialize-complex ] }
283             { CHAR: h [ deserialize-hashtable ] }
284             { CHAR: m [ deserialize-negative-integer ] }
285             { CHAR: n [ deserialize-false ] }
286             { CHAR: t [ deserialize-true ] }
287             { CHAR: o [ deserialize-unknown ] }
288             { CHAR: p [ deserialize-positive-integer ] }
289             { CHAR: q [ deserialize-quotation ] }
290             { CHAR: r [ deserialize-ratio ] }
291             { CHAR: s [ deserialize-string ] }
292             { CHAR: w [ deserialize-word ] }
293             { CHAR: G [ deserialize-word ] }
294             { CHAR: z [ deserialize-zero ] }
295         } case t
296     ] [
297         f f
298     ] if* ;
299
300 : (deserialize) ( -- obj )
301     deserialize* [ "End of stream" throw ] unless ;
302
303 PRIVATE>
304
305 : deserialize ( -- obj )
306     V{ } clone deserialized
307     [ (deserialize) ] with-variable ;
308
309 : serialize ( obj -- )
310     H{ } clone serialized [ (serialize) ] with-variable ;
311
312 : bytes>object ( bytes -- obj )
313     binary [ deserialize ] with-byte-reader ;
314
315 : object>bytes ( obj -- bytes )
316     binary [ serialize ] with-byte-writer ;