root/trunk/lua/data.d

Revision 314, 15.4 kB (checked in by xammy, 3 weeks ago)

Bugfixes for LuaLib (package library, thread destruction)

Line 
1 /*******************************************************************************
2
3     copyright:      Copyright (c) 2008 Matthias Walter. All rights reserved
4
5     authors:        Matthias Walter, Andreas Hollandt
6
7 *******************************************************************************/
8
9 module lua.data;
10
11 private import lua.lua;
12 private import lua.buffer, lua.mixins, lua.error, lua.state;
13
14
15 version (Tango)
16 {
17     private import TangoFloat = tango.text.convert.Float;
18     alias TangoFloat.toString float2string;
19 }
20 else
21 {
22     private import std.string : float2string = toString;
23 }
24
25 /*******************************************************************************
26
27     LuaObject is the base-class for all classes which represent Lua types in
28     the D world. Nil, Threads, Numbers, Bool, Strings, LightUserdata, Tables and
29     C functions are complete and independent of this Lua state, Userdata only
30     contains the pointer and Lua functions are not supported yet.
31
32     This is useful for stack traces (see LuaStackTrace) and to save a Lua
33     value (or whole tables) in a binary format.
34
35 *******************************************************************************/
36
37 abstract class LuaObject
38 {
39     /// Pushes this Lua Object onto the stack of the given Lua State.
40     public abstract void push (LuaState state);
41
42     /// Returns a user-friendly string representation of the Object.
43     public abstract char[] toString ();
44
45     /// Size of the header (currently only the LuaType in binary form.)
46     protected const byte HEADER_SIZE = LuaType.sizeof;
47
48     /***************************************************************************
49
50         Allocates a memory chunk with HEADER_SIZE + size bytes and fills
51         the header properly.
52
53         Params:
54         size = Size for additional data.
55         type = Type to write into the header.
56
57     ***************************************************************************/
58
59     protected byte[] writeHeader (uint size, LuaType type)
60     {
61         byte[] result = new byte[HEADER_SIZE + size];
62         * (cast (LuaType*) &result[0]) = type;
63         return result;
64     }
65
66     /// Method which returns the binary representation of the Object.
67     public abstract byte[] save ();
68
69     /// Method which fills the Object. Do not call this directly.
70     public abstract uint load (byte[] data);
71
72     /***************************************************************************
73
74         Constructs a Lua Object from a given binary representation.
75
76         Params:
77         bytes_read = Number of bytes read.
78         data = Binary data, containing all information.
79
80     ***************************************************************************/
81
82     public static LuaObject load (byte[] data, ref uint bytes_read)
83     {
84         if (data.length < HEADER_SIZE)
85             throw new LuaFatalException ("Invalid stream: Could not read header.");
86
87         LuaObject result;
88
89         switch (* (cast (LuaType*) &data[0]))
90         {
91             case LuaType.NIL: result = new LuaNilObject (); break;
92             case LuaType.NUMBER: result = new LuaNumberObject (); break;
93             case LuaType.STRING: result = new LuaStringObject (); break;
94             case LuaType.FUNCTION: result = new LuaFunctionObject (); break;
95             case LuaType.USERDATA: result = new LuaUserdataObject (); break;
96             case LuaType.BOOL: result = new LuaBoolObject (false); break;
97             case LuaType.TABLE: result = new LuaTableObject (); break;
98             default:
99                 throw new LuaFatalException ("Invalid stream: Wrong type code " ~ int2string (cast (int) * (cast (LuaType*) &data[0])));
100         }
101         bytes_read = HEADER_SIZE;
102         bytes_read += result.load (data[HEADER_SIZE .. length]);
103
104         return result;
105     }
106 }
107
108 /*******************************************************************************
109
110     LuaNilObject represents the Lua type Nil in the D world and can be
111     saved into / loaded from a binary representation.
112
113 *******************************************************************************/
114
115 class LuaNilObject : LuaObject
116 {
117     /// Constructs a LuaNilObject.
118    
119     public this ()
120     {
121
122     }
123    
124     /// Pushes Nil onto the stack.
125
126     public void push (LuaState state)
127     {
128         state.pushNil ();
129     }
130    
131     /// Returns the string representation.
132
133     public override char[] toString ()
134     {
135         return "nil";
136     }
137    
138     /// Saves it as binary array.
139
140     public override byte[] save ()
141     {
142         return writeHeader (0, LuaType.NIL);
143     }
144    
145     /// Fills it from a binary array.
146
147     public override uint load (byte[] data)
148     {
149         return 0;
150     }
151 }
152
153 /*******************************************************************************
154
155     LuaThreadObject represents a Lua Thead in the D world and can be
156     saved into / loaded from a binary representation.
157
158 *******************************************************************************/
159
160 class LuaThreadObject : LuaObject
161 {
162     /// Constructs a LuaThreadObject.
163    
164     public this ()
165     {
166
167     }
168    
169     /// You cannot push a saved Thread into a LuaState!
170
171     public void push (LuaState state)
172     {
173         throw new LuaFatalException ("Error in LuaThreadObject: Cannot push threads.");
174     }
175    
176     /// Returns the string representation.
177
178     public override char[] toString ()
179     {
180         return "thread";
181     }
182
183     /// Saves it as binary array.
184
185     public override byte[] save ()
186     {
187         return writeHeader (0, LuaType.THREAD);
188     }
189    
190     /// Fills it from a binary array.
191
192     public override uint load (byte[] data)
193     {
194         return 0;
195     }
196 }
197
198 /*******************************************************************************
199
200     LuaNumberObject represents the Lua type Number in the D world and can be
201     saved into / loaded from a binary representation.
202
203 *******************************************************************************/
204
205 class LuaNumberObject : LuaObject
206 {
207     /// The numerical value
208     private LuaNumber value_;
209    
210     /// Constructs a LuaNumberObject with a given value.
211
212     public this (LuaNumber value = 0)
213     {
214         this.value_ = value;
215     }
216    
217     /// Pushes the value onto the stack.
218
219     public void push (LuaState state)
220     {
221         state.pushNumber (this.value_);
222     }
223    
224     /// Sets the value.
225    
226     public LuaNumber value (LuaNumber v)
227     {
228         return (this.value_ = v);
229     }
230    
231     /// Returns the value.
232
233     public LuaNumber value ()
234     {
235         return this.value_;
236     }
237    
238     /// Returns the string representation.
239
240     public override char[] toString ()
241     {
242             return float2string (this.value_);
243     }
244    
245     /// Saves it as binary array.
246    
247     public override byte[] save ()
248     {
249         byte[] result = writeHeader (double.sizeof, LuaType.NUMBER);
250         *(cast (double*) &result[HEADER_SIZE]) = this.value_;
251         return result;
252     }
253
254     /// Fills it from a binary array.
255
256     public override uint load (byte[] data)
257     {
258         if (data.length < double.sizeof)
259             throw new LuaFatalException ("Invalid stream: Could not read Number.");
260
261         this.value_ = *(cast (double*) data.ptr);
262
263         return double.sizeof;
264     }
265 }
266
267 /*******************************************************************************
268
269     LuaBoolObject represents the Lua type Bool in the D world and can be
270     saved into / loaded from a binary representation.
271
272 *******************************************************************************/
273
274 class LuaBoolObject : LuaObject
275 {
276     /// Boolean value
277     private bool value_;
278
279     /// Constructs a LuaBoolObject.
280    
281     public this (bool value)
282     {
283         this.value_ = value;
284     }
285    
286     /// Pushes the bool value onto the Lua stack.
287
288     public void push (LuaState state)
289     {
290         state.pushBool (this.value_);
291     }
292    
293     /// Sets the value.
294    
295     public bool value (bool v)
296     {
297         return (this.value_ = v);
298     }
299    
300     /// Returns the value.
301
302     public bool value ()
303     {
304         return this.value_;
305     }
306    
307     /// Returns the string representation.
308
309     public override char[] toString ()
310     {
311         return this.value_ ? "true" : "false";
312     }
313    
314     /// Saves it as binary array.
315    
316     public override byte[] save ()
317     {
318         byte[] result = writeHeader (bool.sizeof, LuaType.BOOL);
319         *(cast (bool*) &result[HEADER_SIZE]) = this.value_;
320         return result;
321     }
322
323     /// Fills it from a binary array.
324
325     public override uint load (byte[] data)
326     {
327         if (data.length < bool.sizeof)
328             throw new LuaFatalException ("Invalid stream: Could not read Boolean.");
329
330         this.value_ = *(cast (bool*) data.ptr);
331
332         return bool.sizeof;
333     }
334 }
335
336 /*******************************************************************************
337
338     LuaStringObject represents the Lua type String in the D world and can be
339     saved into / loaded from a binary representation.
340
341 *******************************************************************************/
342
343 class LuaStringObject : LuaObject
344 {
345     /// String value
346     private char[] value_;
347
348     /// Constructs a LuaStringObject.
349    
350     public this (char[] value = "")
351     {
352         this.value_ = value;
353     }
354    
355     /// Pushes the string onto the Lua stack.
356
357     public void push (LuaState state)
358     {
359         state.pushString (this.value_);
360     }
361    
362     /// Sets the value.
363    
364     public char[] value (char[] v)
365     {
366         return (this.value_ = v);
367     }
368    
369     /// Returns the value.
370
371     public char[] value ()
372     {
373         return this.value_;
374     }
375    
376     /// Returns the string representation.
377
378     public override char[] toString ()
379     {
380         return "\"" ~ this.value_ ~ "\"";
381     }
382    
383     /// Saves it as binary array.
384
385     public override byte[] save ()
386     {
387         byte[] result = writeHeader (size_t.sizeof + this.value_.length, LuaType.STRING);
388         *(cast (size_t*) &result[HEADER_SIZE]) = this.value_.length;
389         auto p = cast (char*) &result[HEADER_SIZE + size_t.sizeof];
390         p[0 .. this.value_.length] = this.value_;
391
392         return result;
393     }
394
395     /// Fills it from a binary array.
396
397     public override uint load (byte[] data)
398     {
399         if (data.length < size_t.sizeof)
400             throw new LuaFatalException ("Invalid stream: Could not read String length.");
401
402         this.value_ = new char[ *(cast (size_t*) data.ptr) ];
403         if (data.length < size_t.sizeof + this.value_.length)
404             throw new LuaFatalException ("Invalid stream: Could not read String.");
405
406         auto p = cast (char*) &data[size_t.sizeof];
407         this.value_[0 .. length] = p[0 .. this.value_.length];
408
409         return size_t.sizeof + this.value_.length;
410     }
411 }
412
413 /*******************************************************************************
414
415     LuaUserdataObject represents the Lua types Userdata and LightUserdata
416     in the D world and can be saved into / loaded from a binary representation.
417
418 *******************************************************************************/
419
420 class LuaUserdataObject : LuaObject
421 {
422     /// Pointer to the data
423     private void* value_;
424    
425     /// Whether it is LightUserdata
426     private bool is_lightuserdata_;
427    
428     /// Constructs a LuaUserdataObject.
429
430     private this ()
431     {
432
433     }
434    
435     /// Constructs a LuaThreadObject with a given value.
436
437     public this (void* value, bool is_lightuserdata)
438     {
439         this.value_ = value;
440         this.is_lightuserdata_ = is_lightuserdata;
441     }
442    
443     /// Pushes the LightUserdata onto the stack. Throws an error if it is a plain Userdata.
444
445     public void push (LuaState state)
446     {
447         if (this.is_lightuserdata_)
448             state.pushLightUserdata (this.value_);
449         else
450             throw new LuaFatalException ("Error in LuaUserdataObject: Cannot push userdata.");
451     }
452    
453     /// Returns the value.
454
455     public void* value ()
456     {
457         return this.value_;
458     }
459    
460     /// Returns true, if and only if this is LightUserdata.
461
462     public bool isLightUserdata ()
463     {
464         return this.is_lightuserdata_;
465     }
466    
467     /// Returns the string representation.
468
469     public override char[] toString ()
470     {
471         return (this.is_lightuserdata_ ? "LightUserdata: " : "Userdata: ") ~ int2string (cast (int) this.value_);
472     }
473    
474     /// Saves it as binary array.
475
476     public override byte[] save ()
477     {
478         byte[] result = writeHeader ((void*).sizeof, LuaType.USERDATA);
479         *(cast (void**) &result[HEADER_SIZE]) = this.value_;
480         return result;
481     }
482
483     /// Fills it from a binary array.
484
485     public override uint load (byte[] data)
486     {
487         if (data.length < (void*).sizeof)
488             throw new LuaFatalException ("Invalid stream: Could not read Userdata.");
489
490         this.value_ = *(cast (void**) data.ptr);
491
492         return (void*).sizeof;
493     }
494 }
495
496 /*******************************************************************************
497
498     LuaFunctionObject represents Lua and C function in the D world and can be
499     saved into / loaded from a binary representation.
500
501 *******************************************************************************/
502
503 class LuaFunctionObject : LuaObject
504 {
505     /// C function pointer
506     private LuaCFunction value_;
507    
508     /// Constructs a LuaFunctionObject.
509
510     public this (LuaCFunction value = null)
511     {
512         this.value_ = value;
513     }
514    
515     /// Returns the function pointer, or null if it is a Lua function.
516
517     public LuaCFunction value ()
518     {
519         return this.value_;
520     }
521    
522     /// Returns true, if and only if it is a C function.
523
524     public bool isCFunction ()
525     {
526         return this.value_ !is null;
527     }
528    
529     /// Pushes the C function onto the stack.
530
531     public void push (LuaState state)
532     {
533         state.pushCFunction (this.value_);
534     }
535    
536     /// Returns the string representation.
537
538     public override char[] toString ()
539     {
540         if (this.value_ is null)
541             return "Lua function";
542         else
543             return "C function at 0x" ~ int2string (cast (int) this.value_, 16);
544     }
545    
546     /// Saves it as binary array.
547
548     public override byte[] save ()
549     {
550         byte[] result = writeHeader (LuaCFunction.sizeof, LuaType.FUNCTION);
551         *(cast (LuaCFunction*) &result[HEADER_SIZE]) = this.value_;
552         return result;
553     }
554
555     /// Fills it from a binary array.
556
557     public override uint load (byte[] data)
558     {
559         if (data.length < LuaCFunction.sizeof)
560             throw new LuaFatalException ("Invalid stream: Could not read Function.");
561
562         this.value_ = *(cast (LuaCFunction*) data.ptr);
563
564         return LuaCFunction.sizeof;
565     }
566 }
567
568 /*******************************************************************************
569
570     LuaTableObject represents Lua Tables in the D world and can be
571     saved into / loaded from a binary representation.
572
573 *******************************************************************************/
574
575 class LuaTableObject : LuaObject
576 {
577     /// Struct containing key/value pairs.
578     struct KeyValuePair
579     {
580         LuaObject key;
581         LuaObject value;
582     }
583    
584     /// Array of key/value pairs.
585     private KeyValuePair[] data_;
586    
587     /// Constructs a LuaTableObject.
588
589     private this ()
590     {
591
592     }
593    
594     /// Constructs a LuaTableObject from a given index, gathering the complete table.
595
596     public this (LuaState state, int index)
597     {
598         state.pushNil ();
599         while (state.next (index))
600         {
601             KeyValuePair pair;
602             pair.key = state.getObject (state.top-1);
603             pair.value = state.getObject (state.top);
604             this.data_ ~= pair;
605             state.pop ();
606         }
607     }
608
609     /// Pushes onto the stack the complete table.
610
611     public void push (LuaState state)
612     {
613         state.createTable ();
614
615         foreach (pair; this.data_)
616         {
617             pair.key.push (state);
618             pair.value.push (state);
619             state.rawSet (-3);
620         }
621     }
622
623     /// Returns the string representation.
624
625     public override char[] toString ()
626     {
627         if (this.data_ !is null)
628         {
629             char[] result = "{ ";
630             foreach (pair; this.data_)
631             {
632                 result ~= pair.key.toString () ~ "=" ~ pair.value.toString () ~ ", ";
633             }
634             return result[0 .. length-2] ~ " }";
635         }
636         else
637             return "{}";
638     }
639
640     /// Saves it as binary array.
641
642     public override byte[] save ()
643     {
644         byte[][] results = [];
645         int size = 0;
646
647         // fill keys / values
648         for (int i = 0; i < this.data_.length; i++)
649         {
650             auto pair = this.data_[i];
651             byte[] saved_key = pair.key.save ();
652             byte[] saved_value = pair.value.save ();
653             results ~= saved_key ~ saved_value;
654             size += saved_key.length + saved_value.length;
655         }
656
657         byte[] result = writeHeader (uint.sizeof + size, LuaType.TABLE);
658
659         *(cast (uint*) &result[HEADER_SIZE]) = this.data_.length;
660         if (size > 0)
661         {
662             auto p = &result[HEADER_SIZE + uint.sizeof];
663             foreach (byte[] r; results)
664             {
665                 p[0 .. r.length] = r[0 .. r.length];
666                 p += r.length;
667             }
668         }
669
670         return result;
671     }
672
673     /// Fills it from a binary array.
674
675     public override uint load (byte[] data)
676     {
677         if (data.length < uint.sizeof)
678             throw new LuaFatalException ("Invalid stream: Could not read Table.");
679
680         this.data_ = new KeyValuePair [ *(cast (uint*) data.ptr) ];
681         uint read = uint.sizeof;
682
683         foreach (ref pair; this.data_)
684         {
685             uint rd = 0;
686             pair.key = LuaObject.load (data[read .. $], rd);
687             read += rd;
688             pair.value = LuaObject.load (data[read .. $], rd);
689             read += rd;
690         }
691
692         return read;
693     }
694 }
Note: See TracBrowser for help on using the browser.