1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 module capnproto.StructBuilder; 23 24 import std.string : startsWith; 25 import std.traits; 26 27 import java.nio.ByteBuffer; 28 29 import capnproto.AnyPointer; 30 import capnproto.Constants; 31 import capnproto.Data; 32 import capnproto.SegmentBuilder; 33 import capnproto.SegmentReader; 34 import capnproto.StructList; 35 import capnproto.StructReader; 36 import capnproto.StructSize; 37 import capnproto.Text; 38 import capnproto.WireHelpers; 39 40 struct StructBuilder 41 { 42 public: //Variables. 43 SegmentBuilder* segment; 44 int data; //Byte offset to data section. 45 int pointers; //Word offset of pointer section. 46 int dataSize; //In bits. 47 short pointerCount; 48 49 public: //Methods. 50 this(SegmentBuilder* segment, int data, int pointers, int dataSize, short pointerCount) 51 { 52 this.segment = segment; 53 this.data = data; 54 this.pointers = pointers; 55 this.dataSize = dataSize; 56 this.pointerCount = pointerCount; 57 } 58 59 T asReader(T)() 60 { 61 return T(segment.asReader(), data, pointers, dataSize, pointerCount, 0x7fffffff); 62 } 63 64 bool _getBoolField(int offset) 65 { 66 int bitOffset = offset; 67 int position = this.data + (bitOffset / 8); 68 return (this.segment.buffer.get!ubyte(position) & (1 << (bitOffset % 8))) != 0; 69 } 70 71 bool _getBoolField(int offset, bool mask) 72 { 73 return this._getBoolField(offset) ^ mask; 74 } 75 76 void _setBoolField(int offset, bool value) 77 { 78 int bitOffset = offset; 79 byte bitnum = cast(byte)(bitOffset % 8); 80 int position = this.data + (bitOffset / 8); 81 byte oldValue = this.segment.buffer.get!byte(position); 82 this.segment.buffer.put!ubyte(position, cast(byte)((oldValue & (~(1 << bitnum))) | ((value? 1 : 0) << bitnum))); 83 } 84 85 void _setBoolField(int offset, bool value, bool mask) 86 { 87 this._setBoolField(offset, value ^ mask); 88 } 89 90 byte _getByteField(int offset) 91 { 92 return this.segment.buffer.get!byte(this.data + offset); 93 } 94 95 byte _getByteField(int offset, byte mask) 96 { 97 return cast(byte)(this._getByteField(offset) ^ mask); 98 } 99 100 void _setByteField(int offset, byte value) 101 { 102 this.segment.buffer.put!byte(this.data + offset, value); 103 } 104 105 void _setByteField(int offset, byte value, byte mask) 106 { 107 this._setByteField(offset, cast(byte)(value ^ mask)); 108 } 109 110 ubyte _getUbyteField(int offset) 111 { 112 return this.segment.buffer.get!ubyte(this.data + offset); 113 } 114 115 ubyte _getUbyteField(int offset, ubyte mask) 116 { 117 return cast(ubyte)(this._getByteField(offset) ^ mask); 118 } 119 120 void _setUbyteField(int offset, ubyte value) 121 { 122 this.segment.buffer.put!ubyte(this.data + offset, value); 123 } 124 125 void _setUbyteField(int offset, ubyte value, ubyte mask) 126 { 127 this._setUbyteField(offset, cast(ubyte)(value ^ mask)); 128 } 129 130 short _getShortField(int offset) 131 { 132 return this.segment.buffer.get!short(this.data + offset * 2); 133 } 134 135 short _getShortField(int offset, short mask) 136 { 137 return cast(short)(this._getShortField(offset) ^ mask); 138 } 139 140 void _setShortField(int offset, short value) 141 { 142 this.segment.buffer.put!short(this.data + offset * 2, value); 143 } 144 145 void _setShortField(int offset, short value, short mask) 146 { 147 this._setShortField(offset, cast(short)(value ^ mask)); 148 } 149 150 ushort _getUshortField(int offset) 151 { 152 return this.segment.buffer.get!short(this.data + offset * 2); 153 } 154 155 ushort _getUshortField(int offset, ushort mask) 156 { 157 return cast(ushort)(this._getShortField(offset) ^ mask); 158 } 159 160 void _setUshortField(int offset, ushort value) 161 { 162 this.segment.buffer.put!short(this.data + offset * 2, value); 163 } 164 165 void _setUshortField(int offset, ushort value, ushort mask) 166 { 167 this._setShortField(offset, cast(ushort)(value ^ mask)); 168 } 169 170 int _getIntField(int offset) 171 { 172 return this.segment.buffer.get!int(this.data + offset * 4); 173 } 174 175 int _getIntField(int offset, int mask) 176 { 177 return this._getIntField(offset) ^ mask; 178 } 179 180 void _setIntField(int offset, int value) 181 { 182 this.segment.buffer.put!int(this.data + offset * 4, value); 183 } 184 185 void _setIntField(int offset, int value, int mask) 186 { 187 this._setIntField(offset, value ^ mask); 188 } 189 190 uint _getUintField(int offset) 191 { 192 return this.segment.buffer.get!int(this.data + offset * 4); 193 } 194 195 uint _getUintField(int offset, uint mask) 196 { 197 return this._getIntField(offset) ^ mask; 198 } 199 200 void _setUintField(int offset, uint value) 201 { 202 this.segment.buffer.put!int(this.data + offset * 4, value); 203 } 204 205 void _setUintField(int offset, uint value, uint mask) 206 { 207 this._setIntField(offset, value ^ mask); 208 } 209 210 long _getLongField(int offset) 211 { 212 return this.segment.buffer.get!long(this.data + offset * 8); 213 } 214 215 long _getLongField(int offset, long mask) 216 { 217 return this._getLongField(offset) ^ mask; 218 } 219 220 void _setLongField(int offset, long value) 221 { 222 this.segment.buffer.put!long(this.data + offset * 8, value); 223 } 224 225 void _setLongField(int offset, long value, long mask) 226 { 227 this._setLongField(offset, value ^ mask); 228 } 229 230 ulong _getUlongField(int offset) 231 { 232 return this.segment.buffer.get!long(this.data + offset * 8); 233 } 234 235 ulong _getUlongField(int offset, ulong mask) 236 { 237 return this._getLongField(offset) ^ mask; 238 } 239 240 void _setUlongField(int offset, ulong value) 241 { 242 this.segment.buffer.put!long(this.data + offset * 8, value); 243 } 244 245 void _setUlongField(int offset, ulong value, ulong mask) 246 { 247 this._setLongField(offset, value ^ mask); 248 } 249 250 float _getFloatField(int offset) 251 { 252 return this.segment.buffer.get!float(this.data + offset * 4); 253 } 254 255 float _getFloatField(int offset, int mask) 256 { 257 return intBitsToFloat(this.segment.buffer.get!int(this.data + offset * 4) ^ mask); 258 } 259 260 void _setFloatField(int offset, float value) 261 { 262 this.segment.buffer.put!float(this.data + offset * 4, value); 263 } 264 265 void _setFloatField(int offset, float value, int mask) 266 { 267 this.segment.buffer.put!int(this.data + offset * 4, floatToIntBits(value) ^ mask); 268 } 269 270 double _getDoubleField(int offset) 271 { 272 return this.segment.buffer.get!double(this.data + offset * 8); 273 } 274 275 double _getDoubleField(int offset, long mask) 276 { 277 return longBitsToDouble(this.segment.buffer.get!long(this.data + offset * 8) ^ mask); 278 } 279 280 void _setDoubleField(int offset, double value) 281 { 282 this.segment.buffer.put!double(this.data + offset * 8, value); 283 } 284 285 void _setDoubleField(int offset, double value, long mask) 286 { 287 this.segment.buffer.put!long(this.data + offset * 8, doubleToLongBits(value) ^ mask); 288 } 289 290 bool _pointerFieldIsNull(int ptrIndex) 291 { 292 return this.segment.buffer.get!long((this.pointers + ptrIndex) * Constants.BYTES_PER_WORD) == 0; 293 } 294 295 void _clearPointerField(int ptrIndex) 296 { 297 int pointer = this.pointers + ptrIndex; 298 WireHelpers.zeroObject(this.segment, pointer); 299 this.segment.buffer.put!long(pointer * 8, 0L); 300 } 301 302 T.Builder _getPointerField(T)(int index) 303 { 304 alias name = fullyQualifiedName!T; 305 306 static if(is(T : AnyPointer)) 307 return T.Builder(this.segment, this.pointers + index); 308 else static if(is(T : Data)) 309 return WireHelpers.getWritableDataPointer(this.pointers + index, this.segment, null, 0, 0); 310 else static if(is(T : Text)) 311 return WireHelpers.getWritableTextPointer(this.pointers + index, this.segment, null, 0, 0); 312 else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.StructList") || name.startsWith("capnproto.TextList")) 313 return WireHelpers.getWritableListPointer!(T.Builder)(this.pointers + index, this.segment, T.elementSize, null, 0); 314 else 315 return WireHelpers.getWritableStructPointer!(T.Builder)(this.pointers + index, this.segment, T.structSize, null, 0); 316 } 317 318 T.Builder _getPointerField(T)(int index, SegmentReader* defaultSegment, int defaultOffset) 319 { 320 alias name = fullyQualifiedName!T; 321 322 static if(is(T : Data)) 323 return WireHelpers.getWritableDataPointer(this.pointers + index, this.segment, defaultSegment, defaultOffset, 0); 324 else static if(is(T : Text)) 325 return WireHelpers.getWritableTextPointer(this.pointers + index, this.segment, defaultSegment, defaultOffset, 0); 326 else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.TextList")) 327 return WireHelpers.getWritableListPointer!(T.Builder)(this.pointers + index, this.segment, T.elementSize, defaultSegment, defaultOffset); 328 else static if(name.startsWith("capnproto.StructList")) 329 return WireHelpers.getWritableStructListPointer!(T.Builder)(this.pointers + index, this.segment, T.structSize, defaultSegment, defaultOffset); 330 else 331 return WireHelpers.getWritableStructPointer!(T.Builder)(this.pointers + index, this.segment, T.structSize, defaultSegment, defaultOffset); 332 } 333 334 T.Builder _getPointerField(T)(int index, ByteBuffer* defaultBuffer, int defaultOffset, int defaultSize) 335 { 336 static if(is(T : Data)) 337 return WireHelpers.getWritableDataPointer(this.pointers + index, this.segment, defaultBuffer, defaultOffset, defaultSize); 338 else static if(is(T : Text)) 339 return WireHelpers.getWritableTextPointer(this.pointers + index, this.segment, defaultBuffer, defaultOffset, defaultSize); 340 else 341 static assert(0); 342 } 343 344 T.Builder _initPointerField(T)(int index, int elementCount) 345 { 346 alias name = fullyQualifiedName!T; 347 348 static if(is(T : AnyPointer)) 349 { 350 auto result = T.Builder(this.segment, this.pointers + index); 351 result.clear(); 352 return result; 353 } 354 else static if(is(T : Data)) 355 return WireHelpers.initDataPointer(this.pointers + index, this.segment, elementCount); 356 else static if(is(T : Text)) 357 return WireHelpers.initTextPointer(this.pointers + index, this.segment, elementCount); 358 else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.TextList")) 359 return WireHelpers.initListPointer!(T.Builder)(this.pointers + index, this.segment, elementCount, T.elementSize); 360 else static if(name.startsWith("capnproto.StructList")) 361 return WireHelpers.initStructListPointer!(T.Builder)(this.pointers + index, this.segment, elementCount, T.structSize); 362 else 363 return WireHelpers.initStructPointer!(T.Builder)(this.pointers + index, this.segment, T.structSize); 364 } 365 366 void _setPointerField(T)(int index, T.Reader value) 367 { 368 alias name = fullyQualifiedName!T; 369 370 static if(is(T : AnyPointer)) 371 assert(0); 372 else static if(is(T : Data)) 373 WireHelpers.setDataPointer(this.pointers + index, this.segment, value); 374 else static if(is(T : Text)) 375 WireHelpers.setTextPointer(this.pointers + index, this.segment, value); 376 else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.StructList") || name.startsWith("capnproto.TextList")) 377 WireHelpers.setListPointer(this.segment, this.pointers + index, value.b); 378 else 379 WireHelpers.setStructPointer(this.segment, this.pointers + index, value.b); 380 } 381 }