1 /*
2  * Copyright 2016 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16  
17 module flatbuffers.table;
18 
19 import flatbuffers.exception;
20 import flatbuffers.bytebuffer;
21 public import std.typecons;
22 
23 /// Mixin this template to all structs in the generated code derive , and add their own accessors.
24 mixin template Struct(ParentType)
25 {
26     /**
27         Create this Struct.
28     */
29     static ParentType init_(size_t pos, ByteBuffer buffer)
30     {
31         return ParentType(buffer, pos);
32     }
33 
34 private: // Variables.
35     /**
36         disable the constor.
37     */
38     @disable this();
39 	this(ByteBuffer buffer, size_t pos)
40     {
41         this._buffer = buffer;
42         this._pos = pos;
43     }
44 
45     ByteBuffer _buffer;
46 	size_t _pos;
47 }
48 
49 /// Mixin this template to all  tables in the generated code derive , and add their own accessors.
50 mixin template Table(ParentType)
51 {
52     /**
53         Create this Struct as a Table.
54     */
55 	static ParentType init_(size_t pos, ByteBuffer buffer)
56     {
57         return ParentType(buffer, pos);
58     }
59 
60 private:
61     ByteBuffer _buffer;
62 	size_t _pos;
63 
64 private: // Methods.
65     @disable this();
66 	this(ByteBuffer buffer, size_t pos)
67     {
68         this._buffer = buffer;
69         this._pos = pos;
70     }
71 
72     /// Look up a field in the vtable, return an offset into the object, or 0 if the field is not present.
73 	uint __offset(size_t vtableOffset)
74     {
75         auto vtable = _pos - _buffer.get!int(_pos);
76         return vtableOffset < _buffer.get!short(vtable) ? cast(
77             uint) _buffer.get!short(vtable + vtableOffset) : 0;
78     }
79 
80     /// Retrieve the relative offset stored at "offset".
81 	uint __indirect(size_t offset)
82     {
83 		return cast(uint)(offset + _buffer.get!int(offset));
84     }
85 
86     /// Create a D string from UTF-8 data stored inside the flatbuffer.
87 	string __string(size_t offset)
88     {
89         offset += _buffer.get!int(offset);
90         auto len = _buffer.get!uint(offset);
91         auto startPos = offset + uint.sizeof;
92         return cast(string) _buffer.data[startPos .. startPos + len];
93     }
94 
95     /// Get the length of a vector whose offset is stored at "offset" in this object.
96 	uint __vector_len(size_t offset)
97     {
98         offset += _pos;
99         offset += _buffer.get!int(offset);
100         return _buffer.get!uint(offset);
101     }
102 
103     /// Get the start of data of a vector whose offset is stored at "offset" in this object.
104 	uint __dvector(size_t offset)
105     {
106         offset += _pos;
107 		return cast(uint)(offset + _buffer.get!int(offset) + int.sizeof); // Data starts after the length.
108     }
109 
110     /// Initialize any Table-derived type to point to the union at the given offset.
111 	T __union(T)(size_t offset)
112     {
113         offset += _pos;
114         return T.init_((offset + _buffer.get!int(offset)), _buffer);
115     }
116 
117     static bool __has_identifier(ByteBuffer bb, string ident)
118     {
119         import std.string;
120 
121         if (ident.length != fileIdentifierLength)
122             throw new ArgumentException(
123                 format("FlatBuffers: file identifier must be length %s.", fileIdentifierLength),
124                 "ident");
125 
126         for (auto i = 0; i < fileIdentifierLength; i++)
127         {
128             if (ident[i] != cast(char) bb.get!byte(bb.position() + cast(uint)uint.sizeof + i))
129                 return false;
130         }
131 
132         return true;
133     }
134 }
135 
136 import std.traits;
137 
138 /**
139     Iterator for the vector.
140 */
141 struct Iterator(ParentType, ReturnType, string accessor)
142 {
143     static if (isScalarType!(ReturnType) || isSomeString!(ReturnType))
144         alias ApplyType = ReturnType;
145     else
146         alias ApplyType = Nullable!ReturnType;
147 private:
148         ParentType parent;
149     int index;
150 public:
151     this(ParentType parent)
152     {
153         this.parent = parent;
154     }
155 
156     @property int length()
157     {
158         mixin("return parent." ~ accessor ~ "Length;");
159     }
160 
161     @property bool empty()
162     {
163         return index == length;
164     }
165 
166     @property ReturnType popFront()
167     {
168         mixin("return parent." ~ accessor ~ "(++index);");
169     }
170 
171     @property ReturnType front()
172     {
173         mixin("return parent." ~ accessor ~ "(index);");
174     }
175 
176     ReturnType opIndex(int index)
177     {
178         mixin("return parent." ~ accessor ~ "(index);");
179     }
180 
181     int opApply(int delegate(ApplyType) operations)
182     {
183         int result = 0;
184         for (int number = 0; number < length(); ++number)
185         {
186             static if (isScalarType!(ReturnType) || isSomeString!(ReturnType))
187                 result = operations(opIndex(number));
188             else
189                 mixin("result = operations(parent." ~ accessor ~ "(number));");
190             if (result)
191                 break;
192         }
193         return result;
194     }
195 
196     int opApply(int delegate(int, ApplyType) operations)
197     {
198         int result = 0;
199         for (int number = 0; number < length(); ++number)
200         {
201             static if (isScalarType!(ReturnType) || isSomeString!(ReturnType))
202                 result = operations(number, opIndex(number));
203             else
204                 mixin("result = operations(number, parent." ~ accessor ~ "(number));");
205             if (result)
206                 break;
207         }
208         return result;
209     }
210 }