├── .directory ├── .gitignore ├── README.MD ├── dub.json ├── samples ├── dub.sdl ├── monster.fbs └── source │ ├── .directory │ ├── MyGame │ └── Sample │ │ ├── Color.d │ │ ├── Equipment.d │ │ ├── Monster.d │ │ ├── Vec3.d │ │ ├── Weapon.d │ │ └── package.d │ └── app.d └── source └── flatbuffers ├── bytebuffer.d ├── exception.d ├── flatbufferbuilder.d ├── package.d └── table.d /.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2017,7,21,16,13,6 3 | Version=4 4 | 5 | [Settings] 6 | HiddenFilesShown=true 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | *.o 5 | *.obj 6 | *.a 7 | *.so 8 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | please see 2 | -------------------------------------------------------------------------------- /dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flatbuffers", 3 | "description": "D implementation of Google Flatbuffers.", 4 | "copyright": "copyright 2016 putao.com", 5 | "license": "Apache-2.0", 6 | "authors": ["putao.com dlang team"], 7 | "targetType": "library" 8 | } 9 | -------------------------------------------------------------------------------- /samples/dub.sdl: -------------------------------------------------------------------------------- 1 | name "samplesD" 2 | description "A minimal D application." 3 | copyright "Copyright © 2016, dsby" 4 | authors "dsby" 5 | dependency "flatbuffers" path="../" 6 | -------------------------------------------------------------------------------- /samples/monster.fbs: -------------------------------------------------------------------------------- 1 | // Example IDL file for our monster's schema. 2 | 3 | namespace MyGame.Sample; 4 | 5 | enum Color:byte { Red = 0, Green, Blue = 2 } 6 | 7 | union Equipment { Weapon } // Optionally add more tables. 8 | 9 | struct Vec3 { 10 | x:float; 11 | y:float; 12 | z:float; 13 | } 14 | 15 | table Monster { 16 | pos:Vec3; 17 | mana:short = 150; 18 | hp:short = 100; 19 | name:string; 20 | friendly:bool = false (deprecated); 21 | inventory:[ubyte]; 22 | color:Color = Blue; 23 | weapons:[Weapon]; 24 | equipped:Equipment; 25 | } 26 | 27 | table Weapon { 28 | name:string; 29 | damage:short; 30 | } 31 | 32 | root_type Monster; 33 | -------------------------------------------------------------------------------- /samples/source/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2016,4,14,11,20,51 3 | Version=3 4 | 5 | [Settings] 6 | HiddenFilesShown=true 7 | -------------------------------------------------------------------------------- /samples/source/MyGame/Sample/Color.d: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | module MyGame.Sample.Color; 4 | 5 | enum Color : byte 6 | { 7 | Red = 0, 8 | Green = 1, 9 | Blue = 2, 10 | } 11 | 12 | -------------------------------------------------------------------------------- /samples/source/MyGame/Sample/Equipment.d: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | module MyGame.Sample.Equipment; 4 | 5 | enum Equipment : ubyte 6 | { 7 | NONE = 0, 8 | Weapon = 1, 9 | } 10 | 11 | -------------------------------------------------------------------------------- /samples/source/MyGame/Sample/Monster.d: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | module MyGame.Sample.Monster; 4 | 5 | import std.typecons; 6 | import flatbuffers; 7 | 8 | import MyGame.Sample.Vec3; 9 | import MyGame.Sample.Color; 10 | import MyGame.Sample.Weapon; 11 | import MyGame.Sample.Equipment; 12 | struct Monster { 13 | mixin Table!Monster; 14 | 15 | static Monster getRootAsMonster(ByteBuffer _bb) { return Monster.init_(_bb.get!int(_bb.position()) + _bb.position(), _bb); } 16 | @property Nullable!Vec3 pos() { uint o = __offset(4); return o != 0 ? Nullable!Vec3(Vec3.init_(o + _pos, _buffer)) : Nullable!Vec3.init; } 17 | @property short mana() { uint o = __offset(6); return o != 0 ? _buffer.get!short(o + _pos) : 150; } 18 | @property short hp() { uint o = __offset(8); return o != 0 ? _buffer.get!short(o + _pos) : 100; } 19 | @property Nullable!string name() { uint o = __offset(10); return o != 0 ? Nullable!string(__string(o + _pos)) : Nullable!string.init; } 20 | auto inventory() { return Iterator!(Monster, ubyte, "inventory")(this); } 21 | ubyte inventory(uint j) { uint o = __offset(14); return o != 0 ? _buffer.get!ubyte(__dvector(o) + j * 1) : 0; } 22 | @property uint inventoryLength() { uint o = __offset(14); return o != 0 ? __vector_len(o) : 0; } 23 | @property byte color() { uint o = __offset(16); return o != 0 ? _buffer.get!byte(o + _pos) : 2; } 24 | auto weapons() { return Iterator!(Monster, Weapon, "weapons")(this); } 25 | Nullable!Weapon weapons(uint j) { uint o = __offset(18); return o != 0 ? Nullable!Weapon(Weapon.init_(__indirect(__dvector(o) + j * 4), _buffer)) : Nullable!Weapon.init; } 26 | @property uint weaponsLength() { uint o = __offset(18); return o != 0 ? __vector_len(o) : 0; } 27 | @property ubyte equippedType() { uint o = __offset(20); return o != 0 ? _buffer.get!ubyte(o + _pos) : 0; } 28 | Nullable!T equipped(T)() { uint o = __offset(22); return o != 0 ? Nullable!T(__union!(T)(o)) : Nullable!T.init; } 29 | 30 | static void startMonster(FlatBufferBuilder builder) { builder.startObject(10); } 31 | static void addPos(FlatBufferBuilder builder, uint posOffset) { builder.addStruct(0, posOffset, 0); } 32 | static void addMana(FlatBufferBuilder builder, short mana) { builder.add!short(1, mana, 150); } 33 | static void addHp(FlatBufferBuilder builder, short hp) { builder.add!short(2, hp, 100); } 34 | static void addName(FlatBufferBuilder builder, uint nameOffset) { builder.addOffset(3, nameOffset, 0); } 35 | static void addInventory(FlatBufferBuilder builder, uint inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); } 36 | static uint createInventoryVector(FlatBufferBuilder builder, ubyte[] data) { builder.startVector(1, cast(uint)data.length, 1); for (size_t i = data.length; i > 0; i--) builder.add!ubyte(data[i - 1]); return builder.endVector(); } 37 | static void startInventoryVector(FlatBufferBuilder builder, uint numElems) { builder.startVector(1, numElems, 1); } 38 | static void addColor(FlatBufferBuilder builder, byte color) { builder.add!byte(6, color, 2); } 39 | static void addWeapons(FlatBufferBuilder builder, uint weaponsOffset) { builder.addOffset(7, weaponsOffset, 0); } 40 | static uint createWeaponsVector(FlatBufferBuilder builder, uint[] data) { builder.startVector(4, cast(uint)data.length, 4); for (size_t i = data.length; i > 0; i--) builder.addOffset(data[i - 1]); return builder.endVector(); } 41 | static void startWeaponsVector(FlatBufferBuilder builder, uint numElems) { builder.startVector(4, numElems, 4); } 42 | static void addEquippedType(FlatBufferBuilder builder, ubyte equippedType) { builder.add!ubyte(8, equippedType, 0); } 43 | static void addEquipped(FlatBufferBuilder builder, uint equippedOffset) { builder.addOffset(9, equippedOffset, 0); } 44 | static uint endMonster(FlatBufferBuilder builder) { 45 | uint o = builder.endObject(); 46 | return o; 47 | } 48 | static void finishMonsterBuffer(FlatBufferBuilder builder, uint offset) { builder.finish(offset); } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /samples/source/MyGame/Sample/Vec3.d: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | module MyGame.Sample.Vec3; 4 | 5 | import std.typecons; 6 | import flatbuffers; 7 | 8 | struct Vec3 { 9 | mixin Struct!Vec3; 10 | 11 | @property float x() { return _buffer.get!float(_pos + 0); } 12 | @property float y() { return _buffer.get!float(_pos + 4); } 13 | @property float z() { return _buffer.get!float(_pos + 8); } 14 | 15 | static uint createVec3(FlatBufferBuilder builder, float x, float y, float z) { 16 | builder.prep(4, 12); 17 | builder.put!float(z); 18 | builder.put!float(y); 19 | builder.put!float(x); 20 | return builder.offset(); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /samples/source/MyGame/Sample/Weapon.d: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | module MyGame.Sample.Weapon; 4 | 5 | import std.typecons; 6 | import flatbuffers; 7 | 8 | struct Weapon { 9 | mixin Table!Weapon; 10 | 11 | static Weapon getRootAsWeapon(ByteBuffer _bb) { return Weapon.init_(_bb.get!int(_bb.position()) + _bb.position(), _bb); } 12 | @property Nullable!string name() { uint o = __offset(4); return o != 0 ? Nullable!string(__string(o + _pos)) : Nullable!string.init; } 13 | @property short damage() { uint o = __offset(6); return o != 0 ? _buffer.get!short(o + _pos) : 0; } 14 | 15 | static uint createWeapon(FlatBufferBuilder builder,uint name,short damage) { 16 | builder.startObject(2); 17 | Weapon.addName(builder, name); 18 | Weapon.addDamage(builder, damage); 19 | return Weapon.endWeapon(builder); 20 | } 21 | 22 | static void startWeapon(FlatBufferBuilder builder) { builder.startObject(2); } 23 | static void addName(FlatBufferBuilder builder, uint nameOffset) { builder.addOffset(0, nameOffset, 0); } 24 | static void addDamage(FlatBufferBuilder builder, short damage) { builder.add!short(1, damage, 0); } 25 | static uint endWeapon(FlatBufferBuilder builder) { 26 | uint o = builder.endObject(); 27 | return o; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /samples/source/MyGame/Sample/package.d: -------------------------------------------------------------------------------- 1 | // automatically generated, do not modify 2 | 3 | module MyGame.Sample; 4 | 5 | public import std.typecons; 6 | public import flatbuffers; 7 | 8 | public import MyGame.Sample.Color; 9 | public import MyGame.Sample.Equipment; 10 | public import MyGame.Sample.Vec3; 11 | public import MyGame.Sample.Monster; 12 | public import MyGame.Sample.Weapon; 13 | -------------------------------------------------------------------------------- /samples/source/app.d: -------------------------------------------------------------------------------- 1 | import std.stdio; 2 | import MyGame.Sample; 3 | //import std.file; 4 | import std.conv; 5 | 6 | void main() 7 | { 8 | writeln("Edit source/app.d to start your project."); 9 | 10 | auto builder = new FlatBufferBuilder(512); 11 | 12 | auto name = builder.createString("MyMonster"); 13 | 14 | uint[] weaps; 15 | foreach ( i ; 0..3){ 16 | weaps ~= Weapon.createWeapon(builder,builder.createString("Weapon." ~ i.to!string()),cast(short)i); 17 | } 18 | uint t = Monster.createWeaponsVector(builder,weaps); 19 | 20 | ubyte[] invData = cast(ubyte[])("MyMonster"); 21 | auto inventory = Monster.createInventoryVector(builder, invData); //todo:数组错误 22 | //Create monster: 23 | Monster.startMonster(builder); 24 | Monster.addPos(builder, Vec3.createVec3(builder, 1, 2, 3)); 25 | Monster.addMana(builder, 150); 26 | Monster.addHp(builder, 80); 27 | Monster.addName(builder, name); 28 | Monster.addInventory(builder, inventory); 29 | Monster.addColor(builder, Color.Blue); 30 | Monster.addWeapons(builder,t); 31 | auto mloc = Monster.endMonster(builder); 32 | 33 | builder.finish(mloc); 34 | //We now have a FlatBuffer we can store or send somewhere. 35 | 36 | //** file/network code goes here :) ** 37 | //access builder.sizedByteArray() for builder.sizedByteArray().length bytes 38 | 39 | //Instead, we're going to access it straight away. 40 | //Get access to the root: 41 | auto data = builder.sizedByteArray(); 42 | //std.file.write("data",data); 43 | //writeln("write serialized data in file data!"); 44 | 45 | //auto rdata = cast(ubyte[])(std.file.read("data")); 46 | auto monster = Monster.getRootAsMonster(new ByteBuffer(data)); 47 | 48 | assert(monster.hp == 80); 49 | assert(monster.mana == 150); //default 50 | assert(monster.name == "MyMonster"); 51 | 52 | auto pos = monster.pos(); 53 | assert(!pos.isNull()); 54 | assert(pos.z == 3); 55 | 56 | auto hh = monster.inventory(); 57 | assert(hh.length == 9); 58 | assert(hh[2] == 'M'); 59 | 60 | 61 | auto weapons = monster.weapons(); 62 | assert(weapons.length == 3); 63 | Nullable!Weapon weap = weapons[1]; 64 | assert(!weap.isNull()); 65 | assert(weap.damage == 1); 66 | assert(weap.name == "Weapon.1"); 67 | writeln("un serialize data over!"); 68 | } 69 | -------------------------------------------------------------------------------- /source/flatbuffers/bytebuffer.d: -------------------------------------------------------------------------------- 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.bytebuffer; 18 | 19 | import std.exception; 20 | import std.bitmanip; 21 | import std.exception; 22 | import core.exception; 23 | 24 | /** 25 | Class warp a ubyte[] to provide byte handle. 26 | */ 27 | 28 | final class ByteBuffer 29 | { 30 | public: 31 | this(){} 32 | 33 | /// init ByteBuffer obj with buffer data 34 | this(ubyte[] buffer) 35 | { 36 | restData(buffer,0); 37 | } 38 | 39 | /// Returns buffer length 40 | @property size_t length() 41 | { 42 | return _buffer.length; 43 | } 44 | 45 | /// Returns buffer data 46 | @property ubyte[] data() 47 | { 48 | return _buffer; 49 | } 50 | 51 | /// Returns buffer position 52 | @property size_t position() 53 | { 54 | return _pos; 55 | } 56 | /// put boolen value into buffer 57 | void put(T)(size_t offset, T value) if (is(T == bool)) 58 | { 59 | put!ubyte(offset, (value ? 0x01 : 0x00)); 60 | } 61 | 62 | /// put byte value into buffer 63 | void put(T)(size_t offset, T value) if (isByte!T) 64 | { 65 | mixin(verifyOffset!1); 66 | _buffer[offset] = value; 67 | _pos = offset; 68 | } 69 | 70 | /// put numbirc value into buffer 71 | void put(T)(size_t offset, T value) if (isNum!T) 72 | { 73 | mixin(verifyOffset!(T.sizeof)); 74 | version (FLATBUFFER_BIGENDIAN) 75 | { 76 | auto array = nativeToBigEndian!T(value); 77 | _buffer[offset .. (offset + T.sizeof)] = array[]; 78 | } 79 | else 80 | { 81 | auto array = nativeToLittleEndian!T(value); 82 | _buffer[offset .. (offset + T.sizeof)] = array[]; 83 | } 84 | _pos = offset; 85 | } 86 | 87 | ///get Byte value in buffer from index 88 | T get(T)(size_t index) if (isByte!T) 89 | { 90 | return cast(T) _buffer[index]; 91 | } 92 | 93 | T get(T)(size_t index) if(is(T == bool)) 94 | { 95 | ubyte value = get!ubyte(index); 96 | return (value ==0x01 ? true : false); 97 | } 98 | 99 | T get(T)(size_t index) if (isNum!T) 100 | { 101 | ubyte[T.sizeof] buf = _buffer[index .. (index + T.sizeof)]; 102 | version (FLATBUFFER_BIGENDIAN) 103 | return bigEndianToNative!(T, T.sizeof)(buf); 104 | else 105 | return littleEndianToNative!(T, T.sizeof)(buf); 106 | } 107 | 108 | void restData(ubyte[] buffer,size_t pos){ 109 | _buffer = buffer; 110 | _pos = pos; 111 | } 112 | 113 | private: /// Variables. 114 | ubyte[] _buffer; 115 | size_t _pos; /// Must track start of the buffer. 116 | } 117 | 118 | unittest 119 | { 120 | ByteBuffer buf = new ByteBuffer(new ubyte[50]); 121 | int a = 10; 122 | buf.put(5, a); 123 | short t = 4; 124 | buf.put(9, t); 125 | 126 | assert(buf.get!int(5) == 10); 127 | assert(buf.get!short(9) == 4); 128 | 129 | } 130 | /*********************************** 131 | * test for boolen value 132 | */ 133 | unittest 134 | { 135 | ByteBuffer buf = new ByteBuffer(new ubyte[50]); 136 | bool a = true; 137 | buf.put(5, a); 138 | bool b = false; 139 | buf.put(9, b); 140 | assert(buf.get!bool(5) == true); 141 | assert(buf.get!bool(9) == false); 142 | 143 | } 144 | private: 145 | template verifyOffset(size_t length) 146 | { 147 | enum verifyOffset = "if(offset < 0 || offset >= _buffer.length || (offset + " ~ length.stringof ~ ") > _buffer.length) throw new RangeError();"; 148 | } 149 | 150 | template isNum(T) 151 | { 152 | static if (is(T == short) || is(T == ushort) || is(T == int) || is(T == uint) 153 | || is(T == long) || is(T == ulong) || is(T == float) || is(T == double)) 154 | enum isNum = true; 155 | else 156 | enum isNum = false; 157 | } 158 | 159 | template isByte(T) 160 | { 161 | static if (is(T == byte) || is(T == ubyte)) 162 | enum isByte = true; 163 | else 164 | enum isByte = false; 165 | } 166 | -------------------------------------------------------------------------------- /source/flatbuffers/exception.d: -------------------------------------------------------------------------------- 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.exception; 18 | 19 | import std.exception; 20 | 21 | ///The number of bytes in a file identifier. 22 | enum fileIdentifierLength = 4; 23 | 24 | ///ArgumentException 25 | class ArgumentException : Exception 26 | { 27 | this(string msg, string argument) pure nothrow @safe 28 | { 29 | super(msg); 30 | } 31 | } 32 | 33 | ///ArgumentOutOfRangeException 34 | class ArgumentOutOfRangeException : Exception 35 | { 36 | this(string argument, long value, string msg) pure nothrow @safe 37 | { 38 | import std.conv : to; 39 | 40 | super(argument ~ ' ' ~ msg ~ " (instead: " ~ value.to!string ~ ")"); 41 | } 42 | } 43 | 44 | ///InvalidOperationException 45 | class InvalidOperationException : Exception 46 | { 47 | this(string msg) pure nothrow @safe 48 | { 49 | super(msg); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /source/flatbuffers/flatbufferbuilder.d: -------------------------------------------------------------------------------- 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.flatbufferbuilder; 18 | 19 | import flatbuffers.exception; 20 | import flatbuffers.bytebuffer; 21 | 22 | import std.exception; 23 | import std.traits : isNumeric; 24 | 25 | /** 26 | Responsible for building up and accessing a FlatBuffer formatted byte 27 | */ 28 | final class FlatBufferBuilder 29 | { 30 | /** 31 | Create a FlatBufferBuilder with a given initial size. 32 | Params: 33 | initsize = The initial size to use for the internal buffer. 34 | */ 35 | this(size_t initsize = 32) 36 | in{ 37 | assert(initsize > 0); 38 | }body{ 39 | this(new ByteBuffer(new ubyte[initsize])); 40 | } 41 | 42 | this(ByteBuffer buffer){ 43 | _space = buffer.length; 44 | _buffer = buffer; 45 | } 46 | 47 | uint offset() 48 | { 49 | return cast(uint)(_buffer.length - _space); 50 | } 51 | 52 | void pad(size_t size) 53 | { 54 | for (int i = 0; i < size; i++) 55 | { 56 | --_space; 57 | _buffer.put!ubyte(_space, 0x00); 58 | } 59 | } 60 | 61 | /** Doubles the size of the ByteBuffer, and copies the old data towards 62 | the end of the new buffer (since we build the buffer backwards). 63 | */ 64 | void growBuffer() 65 | { 66 | auto oldBuf = _buffer.data; 67 | auto oldBufSize = oldBuf.length; 68 | if ((oldBufSize & 0xC0000000) != 0) 69 | throw new Exception("FlatBuffers: cannot grow buffer beyond 2 gigabytes."); 70 | 71 | auto newBufSize = oldBufSize >= 32 ? oldBufSize * 2 : 64; 72 | auto newBuf = new ubyte[](newBufSize); 73 | newBuf[(newBufSize - oldBufSize) .. $] = oldBuf[]; 74 | _buffer.restData(newBuf,0); 75 | } 76 | 77 | /** 78 | Prepare to write an element of `size` after `additional_bytes` 79 | have been written, e.g. if you write a string, you need to align 80 | such the int length field is aligned to SIZEOF_INT, and the string 81 | data follows it directly. 82 | If all you need to do is align, `additional_bytes` will be 0. 83 | */ 84 | void prep(size_t size, size_t additionalBytes) 85 | { 86 | // Track the biggest thing we've ever aligned to. 87 | if (size > _minAlign) 88 | _minAlign = size; 89 | 90 | // Find the amount of alignment needed such that `size` is properly 91 | // aligned after `additional_bytes`. 92 | auto alignSize = ((~( _buffer.length - _space + additionalBytes)) + 1) & (size - 1); 93 | 94 | // Reallocate the buffer if needed. 95 | while (_space < alignSize + size + additionalBytes) 96 | { 97 | auto oldBufSize = cast(int) _buffer.length; 98 | growBuffer(); 99 | _space += cast(int) _buffer.length - oldBufSize; 100 | } 101 | if (alignSize > 0) 102 | pad(alignSize); 103 | } 104 | 105 | /** 106 | put a value into the buffer. 107 | */ 108 | void put(T)(T x) if (is(T == bool) || isNumeric!T) 109 | { 110 | static if (is(T == bool)) 111 | { 112 | _space -= 1; 113 | } 114 | else 115 | { 116 | _space -= T.sizeof; 117 | } 118 | _buffer.put!T(_space, x); 119 | } 120 | 121 | /// Adds a scalar to the buffer, properly aligned, and the buffer grown if needed. 122 | void add(T)(T x)if (is(T == bool) || isNumeric!T) 123 | { 124 | static if (is(T == bool)) 125 | prep(1, 0); 126 | else 127 | prep(T.sizeof, 0); 128 | put!T(x); 129 | } 130 | /// Adds on offset, relative to where it will be written. 131 | void addOffset(uint off) 132 | { 133 | prep(uint.sizeof, 0); // Ensure alignment is already done. 134 | if (off > offset()) 135 | throw new ArgumentException("FlatBuffers: must be less than offset.", "off"); 136 | 137 | off = offset() - off + cast(uint)uint.sizeof; 138 | put!uint(off); 139 | } 140 | 141 | void startVector(int elemSize, int count, int alignment) 142 | { 143 | notNested(); 144 | _vectorNumElems = count; 145 | prep(int.sizeof, elemSize * count); 146 | prep(alignment, elemSize * count); // Just in case alignment > int. 147 | } 148 | 149 | uint endVector() 150 | { 151 | put!int(cast(int)_vectorNumElems); 152 | return offset(); 153 | } 154 | 155 | void nested(int obj) 156 | { 157 | // Structs are always stored inline, so need to be created right 158 | // where they are used. You'll get this assert if you created it 159 | // elsewhere. 160 | if (obj != offset()) 161 | throw new Exception("FlatBuffers: struct must be serialized inline."); 162 | } 163 | 164 | void notNested() 165 | { 166 | // You should not be creating any other objects or strings/vectors 167 | // while an object is being constructed. 168 | if (_vtable) 169 | throw new Exception("FlatBuffers: object serialization must not be nested."); 170 | } 171 | 172 | void startObject(int numfields) 173 | { 174 | if (numfields < 0) 175 | throw new ArgumentOutOfRangeException("numfields", numfields, 176 | "must be greater than zero"); 177 | 178 | notNested(); 179 | _vtable = new size_t[](numfields); 180 | _objectStart = offset(); 181 | } 182 | 183 | /// Set the current vtable at `voffset` to the current location in the buffer. 184 | void slot(size_t voffset) 185 | { 186 | _vtable[voffset] = offset(); 187 | } 188 | 189 | /// Add a scalar to a table at `o` into its vtable, with value `x` and default `d`. 190 | void add(T : bool)(size_t o, T x, T d) 191 | { 192 | if (x != d) 193 | { 194 | add!T(x); 195 | slot(o); 196 | } 197 | } 198 | /// ditto 199 | void add(T)(size_t o, T x, T d) if(isNumeric!T) 200 | { 201 | if (x != d) 202 | { 203 | add!T(x); 204 | slot(o); 205 | } 206 | } 207 | /// ditto 208 | void addOffset(int o, int x, int d) 209 | { 210 | if (x != d) 211 | { 212 | addOffset(x); 213 | slot(o); 214 | } 215 | } 216 | 217 | /** Structs are stored inline, so nothing additional is being added. 218 | `d` is always 0. 219 | */ 220 | void addStruct(int voffset, int x, int d) 221 | { 222 | if (x != d) 223 | { 224 | nested(x); 225 | slot(voffset); 226 | } 227 | } 228 | 229 | /** 230 | Encode the string `s` in the buffer using UTF-8. 231 | Params: 232 | s = The string to encode. 233 | Returns: 234 | The offset in the buffer where the encoded string starts. 235 | */ 236 | uint createString(string s) 237 | { 238 | notNested(); 239 | auto utf8 = cast(ubyte[]) s; 240 | add!ubyte(cast(ubyte) 0); 241 | startVector(1, cast(int) utf8.length, 1); 242 | _space -= utf8.length; 243 | _buffer.data[_space .. _space + utf8.length] = utf8[]; 244 | return endVector(); 245 | } 246 | 247 | uint endObject() 248 | { 249 | if (!_vtable) 250 | throw new InvalidOperationException( 251 | "Flatbuffers: calling endObject without a startObject"); 252 | 253 | add!int(cast(int) 0); 254 | auto vtableloc = offset(); 255 | 256 | // Write out the current vtable. 257 | for (int i = cast(int) _vtable.length - 1; i >= 0; i--) 258 | { 259 | // Offset relative to the start of the table. 260 | short off = cast(short)(_vtable[i] != 0 ? vtableloc - _vtable[i] : 0); 261 | add!short(off); 262 | } 263 | 264 | const int standardFields = 2; // The fields below: 265 | add!short(cast(short)(vtableloc - _objectStart)); 266 | add!short(cast(short)((_vtable.length + standardFields) * short.sizeof)); 267 | 268 | /// Search for an existing vtable that matches the current one. 269 | size_t existingVtable = 0; 270 | 271 | ubyte[] data = _buffer.data(); 272 | 273 | for (int i = 0; i < _numVtables; i++) 274 | { 275 | auto vt1 = _buffer.length - _vtables[i]; 276 | auto vt2 = _space; 277 | short vt1len = _buffer.get!short(vt1); 278 | short vt2len = _buffer.get!short(vt2); 279 | 280 | if (vt1len != vt2len || data[vt1 .. (vt1 + vt1len)] != data[vt2 .. (vt2 + vt2len)]) 281 | continue; 282 | existingVtable = _vtables[i]; 283 | } 284 | 285 | if (existingVtable != 0) 286 | { 287 | // Found a match: 288 | // Remove the current vtable. 289 | _space = _buffer.length - vtableloc; 290 | // Point table to existing vtable. 291 | _buffer.put!int(_space, cast(int)(existingVtable - vtableloc)); 292 | } 293 | else 294 | { 295 | // No match: 296 | // Add the location of the current vtable to the list of vtables. 297 | if (_numVtables == _vtables.length) 298 | _vtables.length *= 2; 299 | _vtables[_numVtables++] = offset(); 300 | // Point table to current vtable. 301 | _buffer.put!int(_buffer.length - vtableloc, offset() - vtableloc); 302 | } 303 | 304 | destroy(_vtable); 305 | _vtable = null; 306 | return vtableloc; 307 | } 308 | 309 | /** This checks a required field has been set in a given table that has 310 | just been constructed. 311 | */ 312 | void required(int table, int field) 313 | { 314 | import std.string; 315 | 316 | auto table_start = _buffer.length - table; 317 | auto vtable_start = table_start - _buffer.get!int(table_start); 318 | bool ok = _buffer.get!short(vtable_start + field) != 0; 319 | // If this fails, the caller will show what field needs to be set. 320 | if (!ok) 321 | throw new InvalidOperationException(format("FlatBuffers: field %s must be set.", 322 | field)); 323 | } 324 | 325 | /** 326 | Finalize a buffer, pointing to the given `root_table`. 327 | Params: 328 | rootTable = An offset to be added to the buffer. 329 | */ 330 | void finish(int rootTable) 331 | { 332 | prep(_minAlign, int.sizeof); 333 | addOffset(rootTable); 334 | } 335 | 336 | /** 337 | Get the ByteBuffer representing the FlatBuffer. 338 | Notes: his is typically only called after you call `Finish()`. 339 | Returns: 340 | Returns the ByteBuffer for this FlatBuffer. 341 | */ 342 | ByteBuffer dataBuffer() 343 | { 344 | return _buffer; 345 | } 346 | 347 | /** 348 | A utility function to copy and return the ByteBuffer data as a `ubyte[]` 349 | Retuens: 350 | the byte used in FlatBuffer data, it is not copy. 351 | */ 352 | ubyte[] sizedByteArray() 353 | { 354 | return _buffer.data[_buffer.position .. $]; 355 | } 356 | 357 | /** 358 | Finalize a buffer, pointing to the given `rootTable`. 359 | Params: 360 | rootTable = An offset to be added to the buffer. 361 | fileIdentifier = A FlatBuffer file identifier to be added to the buffer before `root_table`. 362 | */ 363 | void finish(int rootTable, string fileIdentifier) 364 | { 365 | import std.string; 366 | 367 | prep(_minAlign, int.sizeof + fileIdentifierLength); 368 | if (fileIdentifier.length != fileIdentifierLength) 369 | throw new ArgumentException( 370 | format("FlatBuffers: file identifier must be length %s.", fileIdentifierLength), 371 | "fileIdentifier"); 372 | for (int i = fileIdentifierLength - 1; i >= 0; i--) 373 | add!ubyte(cast(ubyte) fileIdentifier[i]); 374 | addOffset(rootTable); 375 | } 376 | 377 | private: 378 | size_t _space; 379 | ByteBuffer _buffer; 380 | size_t _minAlign = 1; 381 | 382 | /// The vtable for the current table, null otherwise. 383 | size_t[] _vtable; 384 | /// Starting offset of the current struct/table. 385 | size_t _objectStart; 386 | /// List of offsets of all vtables. 387 | size_t[] _vtables = new int[](16); 388 | /// Number of entries in `vtables` in use. 389 | size_t _numVtables = 0; 390 | /// For the current vector being built. 391 | size_t _vectorNumElems = 0; 392 | } 393 | -------------------------------------------------------------------------------- /source/flatbuffers/package.d: -------------------------------------------------------------------------------- 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; 18 | 19 | public import flatbuffers.exception; 20 | public import flatbuffers.bytebuffer; 21 | public import flatbuffers.table; 22 | public import flatbuffers.flatbufferbuilder; -------------------------------------------------------------------------------- /source/flatbuffers/table.d: -------------------------------------------------------------------------------- 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 | } 211 | --------------------------------------------------------------------------------