1 ! Copyright (C) 2006 Adam Langley and Chris Double.
2 ! Adam Langley was the original author of this work.
4 ! Chris Double modified it to fix bugs and get it working
5 ! correctly under the latest versions of Factor.
7 ! See http://factorcode.org/license.txt for BSD license.
9 USING: namespaces sequences kernel math io math.functions
10 io.binary strings classes words sbufs classes.tuple arrays
11 vectors byte-arrays bit-arrays quotations hashtables assocs
12 help.syntax help.markup float-arrays splitting
13 io.streams.byte-array io.encodings.string io.encodings.utf8
14 io.encodings.binary combinators accessors locals prettyprint
15 compiler.units sequences.private classes.tuple.private ;
18 ! Variable holding a assoc of objects already serialized
25 M: id hashcode* obj>> hashcode* ;
27 M: id equal? over id? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
29 : add-object ( obj -- )
30 #! Add an object to the sequence of already serialized
32 serialized get [ assoc-size swap <id> ] keep set-at ;
34 : object-id ( obj -- id )
35 #! Return the id of an already serialized object
36 <id> serialized get at ;
39 GENERIC: (serialize) ( obj -- )
41 ! Numbers are serialized as follows:
43 ! 1<=x<=126 => B{ x | 0x80 }
44 ! x>127 => B{ length(x) x[0] x[1] ... }
45 ! x>2^1024 => B{ 0xff length(x) x[0] x[1] ... }
46 ! The last case is needed because a very large number would
47 ! otherwise be confused with a small number.
48 : serialize-cell ( n -- )
49 dup zero? [ drop 0 write1 ] [
64 : deserialize-cell ( -- n )
66 { [ dup HEX: ff = ] [ drop deserialize-cell read be> ] }
67 { [ dup HEX: 80 >= ] [ HEX: 80 bitxor ] }
68 { [ t ] [ read be> ] }
71 : serialize-shared ( obj quot -- )
73 [ CHAR: o write1 serialize-cell drop ]
76 M: f (serialize) ( obj -- )
79 M: integer (serialize) ( obj -- )
83 dup 0 < [ neg CHAR: m ] [ CHAR: p ] if write1
87 M: float (serialize) ( obj -- )
89 double>bits serialize-cell ;
91 M: complex (serialize) ( obj -- )
93 [ real-part (serialize) ]
94 [ imaginary-part (serialize) ] bi ;
96 M: ratio (serialize) ( obj -- )
98 [ numerator (serialize) ]
99 [ denominator (serialize) ] bi ;
101 : serialize-seq ( obj code -- )
105 [ length serialize-cell ]
106 [ [ (serialize) ] each ] tri
107 ] curry serialize-shared ;
109 M: tuple (serialize) ( obj -- )
112 [ class (serialize) ]
114 [ tuple>array 1 tail (serialize) ]
118 M: array (serialize) ( obj -- )
119 CHAR: a serialize-seq ;
121 M: quotation (serialize) ( obj -- )
124 [ >array (serialize) ] [ add-object ] bi
127 M: hashtable (serialize) ( obj -- )
130 [ add-object ] [ >alist (serialize) ] bi
133 M: bit-array (serialize) ( obj -- )
134 CHAR: b serialize-seq ;
136 M: byte-array (serialize) ( obj -- )
140 [ length serialize-cell ]
144 M: float-array (serialize) ( obj -- )
148 [ length serialize-cell ]
149 [ [ double>bits 8 >be write ] each ]
153 M: string (serialize) ( obj -- )
159 [ length serialize-cell ]
164 : serialize-true ( word -- )
165 drop CHAR: t write1 ;
167 : serialize-gensym ( word -- )
171 [ word-def (serialize) ]
172 [ word-props (serialize) ]
176 : serialize-word ( word -- )
178 [ word-name (serialize) ]
179 [ word-vocabulary (serialize) ]
182 M: word (serialize) ( obj -- )
184 { [ dup t eq? ] [ serialize-true ] }
185 { [ dup word-vocabulary not ] [ serialize-gensym ] }
186 { [ t ] [ serialize-word ] }
189 M: wrapper (serialize) ( obj -- )
191 wrapped (serialize) ;
193 DEFER: (deserialize) ( -- obj )
197 : intern-object ( obj -- )
198 deserialized get push ;
200 : deserialize-false ( -- f )
203 : deserialize-true ( -- f )
206 : deserialize-positive-integer ( -- number )
209 : deserialize-negative-integer ( -- number )
210 deserialize-positive-integer neg ;
212 : deserialize-zero ( -- number )
215 : deserialize-float ( -- float )
216 deserialize-cell bits>double ;
218 : deserialize-ratio ( -- ratio )
219 (deserialize) (deserialize) / ;
221 : deserialize-complex ( -- complex )
222 (deserialize) (deserialize) rect> ;
224 : (deserialize-string) ( -- string )
225 deserialize-cell read utf8 decode ;
227 : deserialize-string ( -- string )
228 (deserialize-string) dup intern-object ;
230 : deserialize-word ( -- word )
231 (deserialize) (deserialize) 2dup lookup
233 "Unknown word: " -rot
234 2array unparse append throw
237 : deserialize-gensym ( -- word )
240 [ (deserialize) define ]
241 [ (deserialize) swap set-word-props ]
245 : deserialize-wrapper ( -- wrapper )
246 (deserialize) <wrapper> ;
248 :: (deserialize-seq) ( exemplar quot -- seq )
249 deserialize-cell exemplar new
251 [ dup [ drop quot call ] change-each ] bi ; inline
253 : deserialize-array ( -- array )
254 { } [ (deserialize) ] (deserialize-seq) ;
256 : deserialize-quotation ( -- array )
257 (deserialize) >quotation dup intern-object ;
259 : deserialize-byte-array ( -- byte-array )
260 B{ } [ read1 ] (deserialize-seq) ;
262 : deserialize-bit-array ( -- bit-array )
263 ?{ } [ (deserialize) ] (deserialize-seq) ;
265 : deserialize-float-array ( -- float-array )
266 F{ } [ 8 read be> bits>double ] (deserialize-seq) ;
268 : deserialize-hashtable ( -- hashtable )
271 [ (deserialize) update ]
274 : copy-seq-to-tuple ( seq tuple -- )
275 >r dup length r> [ set-array-nth ] curry 2each ;
277 : deserialize-tuple ( -- array )
278 #! Ugly because we have to intern the tuple before reading
280 (deserialize) construct-empty
284 [ [ copy-seq-to-tuple ] keep ] bi*
287 : deserialize-unknown ( -- object )
288 deserialize-cell deserialized get nth ;
290 : deserialize* ( -- object ? )
293 { CHAR: A [ deserialize-byte-array ] }
294 { CHAR: F [ deserialize-float ] }
295 { CHAR: T [ deserialize-tuple ] }
296 { CHAR: W [ deserialize-wrapper ] }
297 { CHAR: a [ deserialize-array ] }
298 { CHAR: b [ deserialize-bit-array ] }
299 { CHAR: c [ deserialize-complex ] }
300 { CHAR: f [ deserialize-float-array ] }
301 { CHAR: h [ deserialize-hashtable ] }
302 { CHAR: m [ deserialize-negative-integer ] }
303 { CHAR: n [ deserialize-false ] }
304 { CHAR: t [ deserialize-true ] }
305 { CHAR: o [ deserialize-unknown ] }
306 { CHAR: p [ deserialize-positive-integer ] }
307 { CHAR: q [ deserialize-quotation ] }
308 { CHAR: r [ deserialize-ratio ] }
309 { CHAR: s [ deserialize-string ] }
310 { CHAR: w [ deserialize-word ] }
311 { CHAR: G [ deserialize-word ] }
312 { CHAR: z [ deserialize-zero ] }
318 : (deserialize) ( -- obj )
319 deserialize* [ "End of stream" throw ] unless ;
321 : deserialize ( -- obj )
323 V{ } clone deserialized
324 [ (deserialize) ] with-variable ;
325 ! ] with-compilation-unit ;
327 : serialize ( obj -- )
328 H{ } clone serialized [ (serialize) ] with-variable ;
330 : bytes>object ( bytes -- obj )
331 binary [ deserialize ] with-byte-reader ;
333 : object>bytes ( obj -- bytes )
334 binary [ serialize ] with-byte-writer ;