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 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 ;
18 GENERIC: (serialize) ( obj -- )
22 ! Variable holding a assoc of objects already serialized
29 M: id hashcode* obj>> hashcode* ;
31 M: id equal? over id? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
33 : add-object ( obj -- )
34 #! Add an object to the sequence of already serialized
36 serialized get [ assoc-size swap <id> ] keep set-at ;
38 : object-id ( obj -- id )
39 #! Return the id of an already serialized object
40 <id> serialized get at ;
42 ! Numbers are serialized as follows:
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 ] [
65 : deserialize-cell ( -- n )
67 { [ dup HEX: ff = ] [ drop deserialize-cell read be> ] }
68 { [ dup HEX: 80 >= ] [ HEX: 80 bitxor ] }
72 : serialize-shared ( obj quot -- )
74 [ CHAR: o write1 serialize-cell drop ]
77 M: f (serialize) ( obj -- )
80 M: integer (serialize) ( obj -- )
84 dup 0 < [ neg CHAR: m ] [ CHAR: p ] if write1
88 M: float (serialize) ( obj -- )
90 double>bits serialize-cell ;
92 M: complex (serialize) ( obj -- )
94 [ real-part (serialize) ]
95 [ imaginary-part (serialize) ] bi ;
97 M: ratio (serialize) ( obj -- )
99 [ numerator (serialize) ]
100 [ denominator (serialize) ] bi ;
102 : serialize-seq ( obj code -- )
106 [ length serialize-cell ]
107 [ [ (serialize) ] each ] tri
108 ] curry serialize-shared ;
110 M: tuple (serialize) ( obj -- )
113 [ class (serialize) ]
115 [ tuple>array rest (serialize) ]
119 M: array (serialize) ( obj -- )
120 CHAR: a serialize-seq ;
122 M: quotation (serialize) ( obj -- )
125 [ >array (serialize) ] [ add-object ] bi
128 M: hashtable (serialize) ( obj -- )
131 [ add-object ] [ >alist (serialize) ] bi
134 M: byte-array (serialize) ( obj -- )
138 [ length serialize-cell ]
142 M: string (serialize) ( obj -- )
148 [ length serialize-cell ]
153 : serialize-true ( word -- )
154 drop CHAR: t write1 ;
156 : serialize-gensym ( word -- )
160 [ def>> (serialize) ]
161 [ props>> (serialize) ]
165 : serialize-word ( word -- )
167 [ name>> (serialize) ]
168 [ vocabulary>> (serialize) ]
171 M: word (serialize) ( obj -- )
173 { [ dup t eq? ] [ serialize-true ] }
174 { [ dup vocabulary>> not ] [ serialize-gensym ] }
178 M: wrapper (serialize) ( obj -- )
180 wrapped>> (serialize) ;
182 DEFER: (deserialize) ( -- obj )
186 : intern-object ( obj -- )
187 deserialized get push ;
189 : deserialize-false ( -- f )
192 : deserialize-true ( -- f )
195 : deserialize-positive-integer ( -- number )
198 : deserialize-negative-integer ( -- number )
199 deserialize-positive-integer neg ;
201 : deserialize-zero ( -- number )
204 : deserialize-float ( -- float )
205 deserialize-cell bits>double ;
207 : deserialize-ratio ( -- ratio )
208 (deserialize) (deserialize) / ;
210 : deserialize-complex ( -- complex )
211 (deserialize) (deserialize) rect> ;
213 : (deserialize-string) ( -- string )
214 deserialize-cell read utf8 decode ;
216 : deserialize-string ( -- string )
217 (deserialize-string) dup intern-object ;
219 : deserialize-word ( -- word )
220 (deserialize) (deserialize) 2dup lookup
223 "Unknown word: " -rot
224 2array unparse append throw
227 : deserialize-gensym ( -- word )
230 [ (deserialize) define ]
231 [ (deserialize) >>props drop ]
235 : deserialize-wrapper ( -- wrapper )
236 (deserialize) <wrapper> ;
238 :: (deserialize-seq) ( exemplar quot -- seq )
239 deserialize-cell exemplar new-sequence
241 [ dup [ drop quot call ] change-each ] bi ; inline
243 : deserialize-array ( -- array )
244 { } [ (deserialize) ] (deserialize-seq) ;
246 : deserialize-quotation ( -- array )
247 (deserialize) >quotation dup intern-object ;
249 : deserialize-byte-array ( -- byte-array )
250 B{ } [ read1 ] (deserialize-seq) ;
252 : deserialize-hashtable ( -- hashtable )
255 [ (deserialize) update ]
258 : copy-seq-to-tuple ( seq tuple -- )
259 >r dup length r> [ set-array-nth ] curry 2each ;
261 : deserialize-tuple ( -- array )
262 #! Ugly because we have to intern the tuple before reading
268 [ [ copy-seq-to-tuple ] keep ] bi*
271 : deserialize-unknown ( -- object )
272 deserialize-cell deserialized get nth ;
274 : deserialize* ( -- object ? )
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 ] }
300 : (deserialize) ( -- obj )
301 deserialize* [ "End of stream" throw ] unless ;
305 : deserialize ( -- obj )
306 V{ } clone deserialized
307 [ (deserialize) ] with-variable ;
309 : serialize ( obj -- )
310 H{ } clone serialized [ (serialize) ] with-variable ;
312 : bytes>object ( bytes -- obj )
313 binary [ deserialize ] with-byte-reader ;
315 : object>bytes ( obj -- bytes )
316 binary [ serialize ] with-byte-writer ;