132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2004 Kris Bell. All rights reserved
|
|
4
|
|
5 license: BSD style: $(LICENSE)
|
|
6
|
|
7 version: Oct 2004: Initial release
|
|
8 Dec 2006: Outback release
|
|
9
|
|
10 author: Kris
|
|
11
|
|
12 *******************************************************************************/
|
|
13
|
|
14 module tango.io.protocol.Writer;
|
|
15
|
|
16 private import tango.io.Buffer,
|
|
17 tango.io.FileConst;
|
|
18
|
|
19 public import tango.io.model.IBuffer,
|
|
20 tango.io.model.IConduit;
|
|
21
|
|
22 public import tango.io.protocol.model.IWriter;
|
|
23
|
|
24 private import tango.io.protocol.model.IProtocol;
|
|
25
|
|
26 /*******************************************************************************
|
|
27
|
|
28 Writer base-class. Writers provide the means to append formatted
|
|
29 data to an IBuffer, and expose a convenient method of handling a
|
|
30 variety of data types. In addition to writing native types such
|
|
31 as integer and char[], writers also process any class which has
|
|
32 implemented the IWritable interface (one method).
|
|
33
|
|
34 All writers support the full set of native data types, plus their
|
|
35 fundamental array variants. Operations may be chained back-to-back.
|
|
36
|
|
37 Writers support a Java-esque put() notation. However, the Tango style
|
|
38 is to place IO elements within their own parenthesis, like so:
|
|
39
|
|
40 ---
|
|
41 write (count) (" green bottles");
|
|
42 ---
|
|
43
|
|
44 Note that each written element is distict; this style is affectionately
|
|
45 known as "whisper". The code below illustrates basic operation upon a
|
|
46 memory buffer:
|
|
47
|
|
48 ---
|
|
49 auto buf = new Buffer (256);
|
|
50
|
|
51 // map same buffer into both reader and writer
|
|
52 auto read = new Reader (buf);
|
|
53 auto write = new Writer (buf);
|
|
54
|
|
55 int i = 10;
|
|
56 long j = 20;
|
|
57 double d = 3.14159;
|
|
58 char[] c = "fred";
|
|
59
|
|
60 // write data types out
|
|
61 write (c) (i) (j) (d);
|
|
62
|
|
63 // read them back again
|
|
64 read (c) (i) (j) (d);
|
|
65
|
|
66
|
|
67 // same thing again, but using put() syntax instead
|
|
68 write.put(c).put(i).put(j).put(d);
|
|
69 read.get(c).get(i).get(j).get(d);
|
|
70 ---
|
|
71
|
|
72 Writers may also be used with any class implementing the IWritable
|
|
73 interface, along with any struct implementing an equivalent function.
|
|
74
|
|
75 *******************************************************************************/
|
|
76
|
|
77 class Writer : IWriter
|
|
78 {
|
|
79 // the buffer associated with this writer. Note that this
|
|
80 // should not change over the lifetime of the reader, since
|
|
81 // it is assumed to be immutable elsewhere
|
|
82 package IBuffer buffer_;
|
|
83
|
|
84 package IProtocol.ArrayWriter arrays;
|
|
85 package IProtocol.Writer elements;
|
|
86
|
|
87 // end of line sequence
|
|
88 package char[] eol = FileConst.NewlineString;
|
|
89
|
|
90 /***********************************************************************
|
|
91
|
|
92 Construct a Writer on the provided Protocol
|
|
93
|
|
94 ***********************************************************************/
|
|
95
|
|
96 this (IProtocol protocol)
|
|
97 {
|
|
98 buffer_ = protocol.buffer;
|
|
99 elements = &protocol.write;
|
|
100 arrays = &protocol.writeArray;
|
|
101 }
|
|
102
|
|
103 /***********************************************************************
|
|
104
|
|
105 Construct a Writer on the given OutputStream. We do our own
|
|
106 protocol handling, equivalent to the NativeProtocol.
|
|
107
|
|
108 ***********************************************************************/
|
|
109
|
|
110 this (OutputStream stream)
|
|
111 {
|
|
112 auto b = cast(Buffered) stream;
|
|
113 buffer_ = (b ? b.buffer : new Buffer (stream.conduit));
|
|
114
|
|
115 arrays = &writeArray;
|
|
116 elements = &writeElement;
|
|
117 }
|
|
118
|
|
119 /***********************************************************************
|
|
120
|
|
121 Return the associated buffer
|
|
122
|
|
123 ***********************************************************************/
|
|
124
|
|
125 final IBuffer buffer ()
|
|
126 {
|
|
127 return buffer_;
|
|
128 }
|
|
129
|
|
130 /***********************************************************************
|
|
131
|
|
132 Emit a newline
|
|
133
|
|
134 ***********************************************************************/
|
|
135
|
|
136 IWriter newline ()
|
|
137 {
|
|
138 return put (eol);
|
|
139 }
|
|
140
|
|
141 /***********************************************************************
|
|
142
|
|
143 set the newline sequence
|
|
144
|
|
145 ***********************************************************************/
|
|
146
|
|
147 IWriter newline (char[] eol)
|
|
148 {
|
|
149 this.eol = eol;
|
|
150 return this;
|
|
151 }
|
|
152
|
|
153 /***********************************************************************
|
|
154
|
|
155 Flush the output of this writer and return a chaining ref
|
|
156
|
|
157 ***********************************************************************/
|
|
158
|
|
159 final IWriter flush ()
|
|
160 {
|
|
161 buffer_.flush;
|
|
162 return this;
|
|
163 }
|
|
164
|
|
165 /***********************************************************************
|
|
166
|
|
167 Flush this writer. This is a convenience method used by
|
|
168 the "whisper" syntax.
|
|
169
|
|
170 ***********************************************************************/
|
|
171
|
|
172 final IWriter put ()
|
|
173 {
|
|
174 return flush;
|
|
175 }
|
|
176
|
|
177 /***********************************************************************
|
|
178
|
|
179 Write via a delegate to the current buffer-position
|
|
180
|
|
181 ***********************************************************************/
|
|
182
|
|
183 final IWriter put (IWriter.Closure dg)
|
|
184 {
|
|
185 dg (this);
|
|
186 return this;
|
|
187 }
|
|
188
|
|
189 /***********************************************************************
|
|
190
|
|
191 Write a class to the current buffer-position
|
|
192
|
|
193 ***********************************************************************/
|
|
194
|
|
195 final IWriter put (IWritable x)
|
|
196 {
|
|
197 if (x is null)
|
|
198 buffer_.error ("Writer.put :: attempt to write a null IWritable object");
|
|
199
|
|
200 return put (&x.write);
|
|
201 }
|
|
202
|
|
203 /***********************************************************************
|
|
204
|
|
205 Write a boolean value to the current buffer-position
|
|
206
|
|
207 ***********************************************************************/
|
|
208
|
|
209 final IWriter put (bool x)
|
|
210 {
|
|
211 elements (&x, x.sizeof, IProtocol.Type.Bool);
|
|
212 return this;
|
|
213 }
|
|
214
|
|
215 /***********************************************************************
|
|
216
|
|
217 Write an unsigned byte value to the current buffer-position
|
|
218
|
|
219 ***********************************************************************/
|
|
220
|
|
221 final IWriter put (ubyte x)
|
|
222 {
|
|
223 elements (&x, x.sizeof, IProtocol.Type.UByte);
|
|
224 return this;
|
|
225 }
|
|
226
|
|
227 /***********************************************************************
|
|
228
|
|
229 Write a byte value to the current buffer-position
|
|
230
|
|
231 ***********************************************************************/
|
|
232
|
|
233 final IWriter put (byte x)
|
|
234 {
|
|
235 elements (&x, x.sizeof, IProtocol.Type.Byte);
|
|
236 return this;
|
|
237 }
|
|
238
|
|
239 /***********************************************************************
|
|
240
|
|
241 Write an unsigned short value to the current buffer-position
|
|
242
|
|
243 ***********************************************************************/
|
|
244
|
|
245 final IWriter put (ushort x)
|
|
246 {
|
|
247 elements (&x, x.sizeof, IProtocol.Type.UShort);
|
|
248 return this;
|
|
249 }
|
|
250
|
|
251 /***********************************************************************
|
|
252
|
|
253 Write a short value to the current buffer-position
|
|
254
|
|
255 ***********************************************************************/
|
|
256
|
|
257 final IWriter put (short x)
|
|
258 {
|
|
259 elements (&x, x.sizeof, IProtocol.Type.Short);
|
|
260 return this;
|
|
261 }
|
|
262
|
|
263 /***********************************************************************
|
|
264
|
|
265 Write a unsigned int value to the current buffer-position
|
|
266
|
|
267 ***********************************************************************/
|
|
268
|
|
269 final IWriter put (uint x)
|
|
270 {
|
|
271 elements (&x, x.sizeof, IProtocol.Type.UInt);
|
|
272 return this;
|
|
273 }
|
|
274
|
|
275 /***********************************************************************
|
|
276
|
|
277 Write an int value to the current buffer-position
|
|
278
|
|
279 ***********************************************************************/
|
|
280
|
|
281 final IWriter put (int x)
|
|
282 {
|
|
283 elements (&x, x.sizeof, IProtocol.Type.Int);
|
|
284 return this;
|
|
285 }
|
|
286
|
|
287 /***********************************************************************
|
|
288
|
|
289 Write an unsigned long value to the current buffer-position
|
|
290
|
|
291 ***********************************************************************/
|
|
292
|
|
293 final IWriter put (ulong x)
|
|
294 {
|
|
295 elements (&x, x.sizeof, IProtocol.Type.ULong);
|
|
296 return this;
|
|
297 }
|
|
298
|
|
299 /***********************************************************************
|
|
300
|
|
301 Write a long value to the current buffer-position
|
|
302
|
|
303 ***********************************************************************/
|
|
304
|
|
305 final IWriter put (long x)
|
|
306 {
|
|
307 elements (&x, x.sizeof, IProtocol.Type.Long);
|
|
308 return this;
|
|
309 }
|
|
310
|
|
311 /***********************************************************************
|
|
312
|
|
313 Write a float value to the current buffer-position
|
|
314
|
|
315 ***********************************************************************/
|
|
316
|
|
317 final IWriter put (float x)
|
|
318 {
|
|
319 elements (&x, x.sizeof, IProtocol.Type.Float);
|
|
320 return this;
|
|
321 }
|
|
322
|
|
323 /***********************************************************************
|
|
324
|
|
325 Write a double value to the current buffer-position
|
|
326
|
|
327 ***********************************************************************/
|
|
328
|
|
329 final IWriter put (double x)
|
|
330 {
|
|
331 elements (&x, x.sizeof, IProtocol.Type.Double);
|
|
332 return this;
|
|
333 }
|
|
334
|
|
335 /***********************************************************************
|
|
336
|
|
337 Write a real value to the current buffer-position
|
|
338
|
|
339 ***********************************************************************/
|
|
340
|
|
341 final IWriter put (real x)
|
|
342 {
|
|
343 elements (&x, x.sizeof, IProtocol.Type.Real);
|
|
344 return this;
|
|
345 }
|
|
346
|
|
347 /***********************************************************************
|
|
348
|
|
349 Write a char value to the current buffer-position
|
|
350
|
|
351 ***********************************************************************/
|
|
352
|
|
353 final IWriter put (char x)
|
|
354 {
|
|
355 elements (&x, x.sizeof, IProtocol.Type.Utf8);
|
|
356 return this;
|
|
357 }
|
|
358
|
|
359 /***********************************************************************
|
|
360
|
|
361 Write a wchar value to the current buffer-position
|
|
362
|
|
363 ***********************************************************************/
|
|
364
|
|
365 final IWriter put (wchar x)
|
|
366 {
|
|
367 elements (&x, x.sizeof, IProtocol.Type.Utf16);
|
|
368 return this;
|
|
369 }
|
|
370
|
|
371 /***********************************************************************
|
|
372
|
|
373 Write a dchar value to the current buffer-position
|
|
374
|
|
375 ***********************************************************************/
|
|
376
|
|
377 final IWriter put (dchar x)
|
|
378 {
|
|
379 elements (&x, x.sizeof, IProtocol.Type.Utf32);
|
|
380 return this;
|
|
381 }
|
|
382
|
|
383 /***********************************************************************
|
|
384
|
|
385 Write a boolean array to the current buffer-position
|
|
386
|
|
387 ***********************************************************************/
|
|
388
|
|
389 final IWriter put (bool[] x)
|
|
390 {
|
|
391 arrays (x.ptr, x.length * bool.sizeof, IProtocol.Type.Bool);
|
|
392 return this;
|
|
393 }
|
|
394
|
|
395 /***********************************************************************
|
|
396
|
|
397 Write a byte array to the current buffer-position
|
|
398
|
|
399 ***********************************************************************/
|
|
400
|
|
401 final IWriter put (byte[] x)
|
|
402 {
|
|
403 arrays (x.ptr, x.length * byte.sizeof, IProtocol.Type.Byte);
|
|
404 return this;
|
|
405 }
|
|
406
|
|
407 /***********************************************************************
|
|
408
|
|
409 Write an unsigned byte array to the current buffer-position
|
|
410
|
|
411 ***********************************************************************/
|
|
412
|
|
413 final IWriter put (ubyte[] x)
|
|
414 {
|
|
415 arrays (x.ptr, x.length * ubyte.sizeof, IProtocol.Type.UByte);
|
|
416 return this;
|
|
417 }
|
|
418
|
|
419 /***********************************************************************
|
|
420
|
|
421 Write a short array to the current buffer-position
|
|
422
|
|
423 ***********************************************************************/
|
|
424
|
|
425 final IWriter put (short[] x)
|
|
426 {
|
|
427 arrays (x.ptr, x.length * short.sizeof, IProtocol.Type.Short);
|
|
428 return this;
|
|
429 }
|
|
430
|
|
431 /***********************************************************************
|
|
432
|
|
433 Write an unsigned short array to the current buffer-position
|
|
434
|
|
435 ***********************************************************************/
|
|
436
|
|
437 final IWriter put (ushort[] x)
|
|
438 {
|
|
439 arrays (x.ptr, x.length * ushort.sizeof, IProtocol.Type.UShort);
|
|
440 return this;
|
|
441 }
|
|
442
|
|
443 /***********************************************************************
|
|
444
|
|
445 Write an int array to the current buffer-position
|
|
446
|
|
447 ***********************************************************************/
|
|
448
|
|
449 final IWriter put (int[] x)
|
|
450 {
|
|
451 arrays (x.ptr, x.length * int.sizeof, IProtocol.Type.Int);
|
|
452 return this;
|
|
453 }
|
|
454
|
|
455 /***********************************************************************
|
|
456
|
|
457 Write an unsigned int array to the current buffer-position
|
|
458
|
|
459 ***********************************************************************/
|
|
460
|
|
461 final IWriter put (uint[] x)
|
|
462 {
|
|
463 arrays (x.ptr, x.length * uint.sizeof, IProtocol.Type.UInt);
|
|
464 return this;
|
|
465 }
|
|
466
|
|
467 /***********************************************************************
|
|
468
|
|
469 Write a long array to the current buffer-position
|
|
470
|
|
471 ***********************************************************************/
|
|
472
|
|
473 final IWriter put (long[] x)
|
|
474 {
|
|
475 arrays (x.ptr, x.length * long.sizeof, IProtocol.Type.Long);
|
|
476 return this;
|
|
477 }
|
|
478
|
|
479 /***********************************************************************
|
|
480
|
|
481 Write an unsigned long array to the current buffer-position
|
|
482
|
|
483 ***********************************************************************/
|
|
484
|
|
485 final IWriter put (ulong[] x)
|
|
486 {
|
|
487 arrays (x.ptr, x.length * ulong.sizeof, IProtocol.Type.ULong);
|
|
488 return this;
|
|
489 }
|
|
490
|
|
491 /***********************************************************************
|
|
492
|
|
493 Write a float array to the current buffer-position
|
|
494
|
|
495 ***********************************************************************/
|
|
496
|
|
497 final IWriter put (float[] x)
|
|
498 {
|
|
499 arrays (x.ptr, x.length * float.sizeof, IProtocol.Type.Float);
|
|
500 return this;
|
|
501 }
|
|
502
|
|
503 /***********************************************************************
|
|
504
|
|
505 Write a double array to the current buffer-position
|
|
506
|
|
507 ***********************************************************************/
|
|
508
|
|
509 final IWriter put (double[] x)
|
|
510 {
|
|
511 arrays (x.ptr, x.length * double.sizeof, IProtocol.Type.Double);
|
|
512 return this;
|
|
513 }
|
|
514
|
|
515 /***********************************************************************
|
|
516
|
|
517 Write a real array to the current buffer-position
|
|
518
|
|
519 ***********************************************************************/
|
|
520
|
|
521 final IWriter put (real[] x)
|
|
522 {
|
|
523 arrays (x.ptr, x.length * real.sizeof, IProtocol.Type.Real);
|
|
524 return this;
|
|
525 }
|
|
526
|
|
527 /***********************************************************************
|
|
528
|
|
529 Write a char array to the current buffer-position
|
|
530
|
|
531 ***********************************************************************/
|
|
532
|
|
533 final IWriter put (char[] x)
|
|
534 {
|
|
535 arrays (x.ptr, x.length * char.sizeof, IProtocol.Type.Utf8);
|
|
536 return this;
|
|
537 }
|
|
538
|
|
539 /***********************************************************************
|
|
540
|
|
541 Write a wchar array to the current buffer-position
|
|
542
|
|
543 ***********************************************************************/
|
|
544
|
|
545 final IWriter put (wchar[] x)
|
|
546 {
|
|
547 arrays (x.ptr, x.length * wchar.sizeof, IProtocol.Type.Utf16);
|
|
548 return this;
|
|
549 }
|
|
550
|
|
551 /***********************************************************************
|
|
552
|
|
553 Write a dchar array to the current buffer-position
|
|
554
|
|
555 ***********************************************************************/
|
|
556
|
|
557 final IWriter put (dchar[] x)
|
|
558 {
|
|
559 arrays (x.ptr, x.length * dchar.sizeof, IProtocol.Type.Utf32);
|
|
560 return this;
|
|
561 }
|
|
562
|
|
563 /***********************************************************************
|
|
564
|
|
565 Dump array content into the buffer. Note that the default
|
|
566 behaviour is to prefix with the array byte count
|
|
567
|
|
568 ***********************************************************************/
|
|
569
|
|
570 private void writeArray (void* src, uint bytes, IProtocol.Type type)
|
|
571 {
|
|
572 put (bytes);
|
|
573 writeElement (src, bytes, type);
|
|
574 }
|
|
575
|
|
576 /***********************************************************************
|
|
577
|
|
578 Dump content into the buffer
|
|
579
|
|
580 ***********************************************************************/
|
|
581
|
|
582 private void writeElement (void* src, uint bytes, IProtocol.Type type)
|
|
583 {
|
|
584 buffer_.append (src [0 .. bytes]);
|
|
585 }
|
|
586 }
|