author | Jan Vrany <jan.vrany@fit.cvut.cz> |
Wed, 01 Feb 2012 00:34:28 +0000 | |
changeset 97 | 2a7827f4dce2 |
parent 72 | d16c7d84d4a8 |
child 111 | 44ac233b2f83 |
permissions | -rw-r--r-- |
10 | 1 |
"{ Package: 'stx:goodies/xtreams/transforms' }" |
2 |
||
3 |
"{ NameSpace: Xtreams }" |
|
4 |
||
5 |
Object subclass:#MessagePackMarshaler |
|
6 |
instanceVariableNames:'unmarshaling marshaling analysing' |
|
7 |
classVariableNames:'' |
|
97 | 8 |
poolDictionaries:'Xtreams::XtreamsPool' |
27
2cc5a8a3ca14
added XtreamsPool to fix DefaultBufferSize; set proper category names
mkobetic
parents:
10
diff
changeset
|
9 |
category:'Xtreams-Transforms' |
10 | 10 |
! |
11 |
||
12 |
MessagePackMarshaler comment:'MessagePackMarshaler defines the binary format of the MessagePack protocol ( http://wiki.msgpack.org/display/MSGPACK/Format+specification ), which is a binary JSON. It can marshal simple objects, but not whole classes, just like JSON. It is considered to be a very fast marshaler because of its lightweight protocol. It cannot handle circular references. |
|
13 |
||
14 |
Instance Variables |
|
15 |
analysing <Object> analysing operations |
|
16 |
marshaling <Dictionary> marshaling operations |
|
17 |
unmarshaling <(Array of: (BlockClosure))> unmarshaling operations |
|
18 |
||
19 |
||
20 |
||
21 |
' |
|
22 |
! |
|
23 |
||
24 |
||
25 |
!MessagePackMarshaler class methodsFor:'instance creation'! |
|
26 |
||
27 |
new |
|
28 |
^super new initialize |
|
29 |
! ! |
|
30 |
||
31 |
!MessagePackMarshaler class methodsFor:'constants - containers'! |
|
32 |
||
33 |
array16 |
|
34 |
^16rDC |
|
35 |
! |
|
36 |
||
37 |
array32 |
|
38 |
^16rDD |
|
39 |
! |
|
40 |
||
41 |
map16 |
|
42 |
^16rDE |
|
43 |
! |
|
44 |
||
45 |
map32 |
|
46 |
^16rDF |
|
47 |
! |
|
48 |
||
49 |
raw16 |
|
50 |
^16rDA |
|
51 |
! |
|
52 |
||
53 |
raw32 |
|
54 |
^16rDB |
|
55 |
! ! |
|
56 |
||
57 |
!MessagePackMarshaler class methodsFor:'constants - numbers'! |
|
58 |
||
59 |
double |
|
60 |
^16rCB |
|
61 |
! |
|
62 |
||
63 |
float |
|
64 |
^16rCA |
|
65 |
! |
|
66 |
||
67 |
int16 |
|
68 |
^16rD1 |
|
69 |
! |
|
70 |
||
71 |
int32 |
|
72 |
^16rD2 |
|
73 |
! |
|
74 |
||
75 |
int64 |
|
76 |
^16rD3 |
|
77 |
! |
|
78 |
||
79 |
int8 |
|
80 |
^16rD0 |
|
81 |
! |
|
82 |
||
83 |
uint16 |
|
84 |
^16rCD |
|
85 |
! |
|
86 |
||
87 |
uint32 |
|
88 |
^16rCE |
|
89 |
! |
|
90 |
||
91 |
uint64 |
|
92 |
^16rCF |
|
93 |
! |
|
94 |
||
95 |
uint8 |
|
96 |
^16rCC |
|
97 |
! ! |
|
98 |
||
99 |
!MessagePackMarshaler class methodsFor:'constants - singletons'! |
|
100 |
||
101 |
false |
|
102 |
^16rC2 |
|
103 |
! |
|
104 |
||
105 |
nil |
|
106 |
^16rC0 |
|
107 |
! |
|
108 |
||
109 |
true |
|
110 |
^16rC3 |
|
111 |
! ! |
|
112 |
||
113 |
!MessagePackMarshaler methodsFor:'api'! |
|
114 |
||
115 |
analyse: reading |
|
116 |
| type | |
|
117 |
type := reading uint8 get. |
|
118 |
type <= 16rBF ifTrue: [ |
|
119 |
| fixMapOrArray | |
|
120 |
type <= 16r7F ifTrue: [^reading log: 'positive fixnum' do: [type]]. |
|
121 |
fixMapOrArray := type bitShift: -4. |
|
122 |
fixMapOrArray = 2r1001 ifTrue: [^reading log: 'fix array' do: [(1 to: (type bitAnd: 2r00001111)) collect: [:i | self analyse: reading]]]. |
|
123 |
fixMapOrArray = 2r1000 ifTrue: [ |
|
124 |
^reading log: 'fix map' do: [ |
|
125 |
| map | |
|
126 |
map := Dictionary new. |
|
127 |
(type bitAnd: 2r00001111) timesRepeat: [ |
|
128 |
map at: (self analyse: reading) put: (self analyse: reading)]. |
|
129 |
map]]. |
|
130 |
^reading log: 'fix raw' do: [reading uint8 read: (type bitAnd: 2r00011111)]]. |
|
131 |
(type bitShift: -5) = 2r111 ifTrue: [^reading log: 'negative fixnum' do: [-32 + (type bitAnd: 2r00011111)]]. |
|
132 |
^reading log: (type printStringRadix: 16) do: [(analysing at: type) value: reading] |
|
133 |
! |
|
134 |
||
135 |
marshal: writing object: object |
|
136 |
(marshaling at: object class ifAbsent: [self error: 'Unmarshalable class with the MessagePack protocol']) value: writing value: object |
|
137 |
! |
|
138 |
||
139 |
unmarshal: reading |
|
140 |
| type | |
|
141 |
type := reading uint8 get. |
|
142 |
type <= 16rBF ifTrue: [ |
|
143 |
| fixMapOrArray | |
|
144 |
type <= 16r7F ifTrue: [^type]. |
|
145 |
fixMapOrArray := type bitShift: -4. |
|
146 |
fixMapOrArray = 2r1001 ifTrue: [^(1 to: (type bitAnd: 2r00001111)) collect: [:i | self unmarshal: reading]]. |
|
147 |
fixMapOrArray = 2r1000 ifTrue: [ |
|
148 |
| map | |
|
149 |
map := Dictionary new. |
|
150 |
(type bitAnd: 2r00001111) timesRepeat: [ |
|
151 |
map at: (self unmarshal: reading) put: (self unmarshal: reading)]. |
|
152 |
^map]. |
|
153 |
^reading uint8 read: (type bitAnd: 2r00011111)]. |
|
154 |
(type bitShift: -5) = 2r111 ifTrue: [^-32 + (type bitAnd: 2r00011111)]. |
|
155 |
^(unmarshaling at: type) value: reading |
|
156 |
! ! |
|
157 |
||
158 |
!MessagePackMarshaler methodsFor:'configuration'! |
|
159 |
||
160 |
configureAnalyse: reading |
|
161 |
"This protocol has fixed endianness built in" |
|
162 |
^true |
|
163 |
! |
|
164 |
||
165 |
configureMarshal: writing |
|
166 |
"This protocol has fixed endianness built in" |
|
167 |
^true |
|
168 |
! |
|
169 |
||
170 |
configureUnmarshal: reading |
|
171 |
"This protocol has fixed endianness built in" |
|
172 |
^true |
|
173 |
! ! |
|
174 |
||
175 |
!MessagePackMarshaler methodsFor:'initialize-release'! |
|
176 |
||
177 |
initialize |
|
178 |
self initializeMarshaling. |
|
179 |
self initializeUnmarshaling. |
|
180 |
self initializeAnalysing. |
|
181 |
! |
|
182 |
||
183 |
initializeAnalysing |
|
184 |
(analysing := unmarshaling copy) |
|
185 |
at: self class array16 put: [:reading | reading log: 'array16' do: [(1 to: reading uint16 get) collect: [:i | self analyse: reading]]]; |
|
186 |
at: self class array32 put: [:reading | reading log: 'array32' do: [(1 to: reading uint32 get) collect: [:i | self analyse: reading]]]; |
|
187 |
at: self class map16 put: [:reading | |
|
188 |
reading log: 'map16' do: [ |
|
189 |
| map | |
|
190 |
map := Dictionary new. |
|
191 |
reading uint16 get timesRepeat: [ |
|
192 |
map at: (self analyse: reading) put: (self analyse:reading)]. |
|
193 |
map]]; |
|
194 |
at: self class map32 put: [:reading | |
|
195 |
reading log: 'map32' do: [ |
|
196 |
| map | |
|
197 |
map := Dictionary new. |
|
198 |
reading uint16 get timesRepeat: [ |
|
199 |
map at: (self analyse: reading) put: (self analyse: reading)]. |
|
200 |
map]]; |
|
201 |
yourself |
|
202 |
! |
|
203 |
||
204 |
initializeMarshaling |
|
205 |
(marshaling := Dictionary new) |
|
206 |
"singletons" |
|
207 |
at: UndefinedObject put: [:writing :object | writing uint8 put: self class nil]; |
|
208 |
at: True put: [:writing :object | writing uint8 put: self class true]; |
|
209 |
at: False put: [:writing :object | writing uint8 put: self class false]; |
|
210 |
||
211 |
"numbers" |
|
212 |
at: Float put: [:writing :object | writing uint8 put: self class float. writing float put: object]; |
|
213 |
at: Double put: [:writing :object | writing uint8 put: self class double. writing double put: object]; |
|
214 |
at: SmallDouble put: [:writing :object | writing uint8 put: self class double. writing double put: object]; |
|
215 |
yourself. |
|
216 |
||
217 |
Integer allSubclassesDo: [:each | |
|
218 |
marshaling at: each put: [:writing :object | self write: writing integer: object]]. |
|
219 |
||
220 |
SequenceableCollection allSubclassesDo: [:each | |
|
221 |
marshaling at: each put: [:writing :object | self write: writing array: object]]. |
|
222 |
(KeyedCollection withAllSubclasses, Dictionary withAllSubclasses) do: [:each | |
|
223 |
marshaling at: each put: [:writing :object | self write: writing map: object]]. |
|
224 |
(CharacterArray withAllSubclasses, IntegerArray withAllSubclasses) do: [:each | |
|
225 |
marshaling at: each put: [:writing :object | self error: each name, ' are not supported by the MessagePack protocol']]. |
|
226 |
marshaling at: ByteArray put: [:writing :object | self write: writing raw: object] |
|
227 |
! |
|
228 |
||
229 |
initializeUnmarshaling |
|
230 |
(unmarshaling := Array new: 255 withAll: [:reading | self error: 'unknown type']) |
|
231 |
"singletons" |
|
232 |
at: self class nil put: [:reading | nil]; |
|
233 |
at: self class true put: [:reading | true]; |
|
234 |
at: self class false put: [:reading | false]; |
|
235 |
||
236 |
"numbers" |
|
237 |
at: self class uint8 put: [:reading | reading uint8 get]; |
|
238 |
at: self class uint16 put: [:reading | reading uint16 get]; |
|
239 |
at: self class uint32 put: [:reading | reading uint32 get]; |
|
240 |
at: self class uint64 put: [:reading | reading uint64 get]; |
|
241 |
at: self class int8 put: [:reading | reading int8 get]; |
|
242 |
at: self class int16 put: [:reading | reading int16 get]; |
|
243 |
at: self class int32 put: [:reading | reading int32 get]; |
|
244 |
at: self class int64 put: [:reading | reading int64 get]; |
|
245 |
at: self class float put: [:reading | reading float get]; |
|
246 |
at: self class double put: [:reading | reading double get]; |
|
247 |
||
248 |
"containers" |
|
249 |
at: self class raw16 put: [:reading | reading uint8 read: reading uint16 get]; |
|
250 |
at: self class raw32 put: [:reading | reading uint8 read: reading uint32 get]; |
|
251 |
at: self class array16 put: [:reading | (1 to: reading uint16 get) collect: [:i | self unmarshal: reading]]; |
|
252 |
at: self class array32 put: [:reading | (1 to: reading uint32 get) collect: [:i | self unmarshal: reading]]; |
|
253 |
at: self class map16 put: [:reading | |
|
254 |
| map | |
|
255 |
map := Dictionary new. |
|
256 |
reading uint16 get timesRepeat: [ |
|
257 |
map at: (self unmarshal: reading) put: (self unmarshal: reading)]. |
|
258 |
map]; |
|
259 |
at: self class map32 put: [:reading | |
|
260 |
| map | |
|
261 |
map := Dictionary new. |
|
262 |
reading uint32 get timesRepeat: [ |
|
263 |
map at: (self unmarshal: reading) put: (self unmarshal: reading)]. |
|
264 |
map]; |
|
265 |
yourself |
|
266 |
! ! |
|
267 |
||
268 |
!MessagePackMarshaler methodsFor:'private - writing'! |
|
269 |
||
270 |
write: writing array: array |
|
271 |
self write: writing array_size: array size. |
|
272 |
array do: [:each | self marshal: writing object: each] |
|
273 |
! |
|
274 |
||
275 |
write: writing array_size: size |
|
276 |
size <= 2r00001111 ifTrue: [^writing uint8 put: size + 2r10010000]. |
|
277 |
size <= 65535 ifTrue: [ |
|
278 |
writing uint8 put: self class array16. |
|
279 |
^writing uint16 put: size]. |
|
280 |
size <= 4294967295 ifTrue: [ |
|
281 |
writing uint8 put: self class array32. |
|
282 |
^writing uint32 put: size]. |
|
283 |
self error: 'array too big to marshal with MessagePack protocol' |
|
284 |
! |
|
285 |
||
286 |
write: writing integer: integer |
|
287 |
(integer between: 0 and: 127) ifTrue: [^writing uint8 put: integer]. |
|
288 |
(integer between: -32 and: -1) ifTrue: [^writing uint8 put: integer + 256]. |
|
289 |
integer >= 128 ifTrue: [ |
|
290 |
integer <= 255 ifTrue: [^writing uint8 put: self class uint8; put: integer]. |
|
291 |
integer <= 65535 ifTrue: [ |
|
292 |
writing uint8 put: self class uint16. |
|
293 |
^writing uint16 put: integer]. |
|
294 |
integer <= 4294967295 ifTrue: [ |
|
295 |
writing uint8 put: self class uint32. |
|
296 |
^writing uint32 put: integer]. |
|
297 |
integer <= 18446744073709551615 ifTrue: [ |
|
298 |
writing uint8 put: self class uint64. |
|
299 |
^writing uint64 put: integer]. |
|
300 |
self error: 'integer too big to marshal with MessagePack protocol']. |
|
301 |
integer >= -128 ifTrue: [ |
|
302 |
writing uint8 put: self class int8. |
|
303 |
^writing int8 put: integer]. |
|
304 |
integer >= -32768 ifTrue: [ |
|
305 |
writing uint8 put: self class int16. |
|
306 |
^writing int16 put: integer]. |
|
307 |
integer >= -2147483648 ifTrue: [ |
|
308 |
writing uint8 put: self class int32. |
|
309 |
^writing int32 put: integer]. |
|
310 |
integer >= -9223372036854775808 ifTrue: [ |
|
311 |
writing uint8 put: self class int64. |
|
312 |
^writing int64 put: integer]. |
|
313 |
self error: 'integer too small to marshal with MessagePack protocol'. |
|
314 |
! |
|
315 |
||
316 |
write: writing map: map |
|
317 |
self write: writing map_size: map size. |
|
318 |
map keysAndValuesDo: [:key :value | |
|
319 |
self marshal: writing object: key. |
|
320 |
self marshal: writing object: value] |
|
321 |
! |
|
322 |
||
323 |
write: writing map_size: size |
|
324 |
size <= 2r00001111 ifTrue: [^writing uint8 put: size + 2r10000000]. |
|
325 |
size <= 65535 ifTrue: [ |
|
326 |
writing uint8 put: self class map16. |
|
327 |
^writing uint16 put: size]. |
|
328 |
size <= 4294967295 ifTrue: [ |
|
329 |
writing uint8 put: self class map32. |
|
330 |
^writing uint32 put: size]. |
|
331 |
self error: 'array too big to marshal with MessagePack protocol' |
|
332 |
! |
|
333 |
||
334 |
write: writing raw: bytearray |
|
335 |
self write: writing raw_size: bytearray size. |
|
336 |
writing uint8 write: bytearray |
|
337 |
! |
|
338 |
||
339 |
write: writing raw_size: size |
|
340 |
size <= 2r00011111 ifTrue: [^writing uint8 put: size + 2r10100000]. |
|
341 |
size <= 65535 ifTrue: [ |
|
342 |
writing uint8 put: self class raw16. |
|
343 |
^writing uint16 put: size]. |
|
344 |
size <= 4294967295 ifTrue: [ |
|
345 |
writing uint8 put: self class raw32. |
|
346 |
^writing uint32 put: size]. |
|
347 |
self error: 'array too big to marshal with MessagePack protocol' |
|
348 |
! ! |
|
349 |
||
350 |
!MessagePackMarshaler class methodsFor:'documentation'! |
|
351 |
||
352 |
version_SVN |
|
353 |
^ '$Id$' |
|
354 |
! ! |