1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 2// for details. All rights reserved. Use of this source code is governed by a 3// BSD-style license that can be found in the LICENSE file. 4 5import 'dart:typed_data'; 6import 'dart:io' as io; 7 8import 'package:path/path.dart' as path; 9 10import 'package:flat_buffers/flat_buffers.dart'; 11import 'package:test/test.dart'; 12import 'package:test_reflective_loader/test_reflective_loader.dart'; 13 14import './monster_test_my_game.example_generated.dart' as example; 15 16main() { 17 defineReflectiveSuite(() { 18 defineReflectiveTests(BuilderTest); 19 defineReflectiveTests(CheckOtherLangaugesData); 20 }); 21} 22 23int indexToField(int index) { 24 return (1 + 1 + index) * 2; 25} 26 27@reflectiveTest 28class CheckOtherLangaugesData { 29 test_cppData() async { 30 List<int> data = await new io.File(path.join( 31 path.dirname(io.Platform.script.path), 32 'monsterdata_test.mon', 33 )) 34 .readAsBytes(); 35 example.Monster mon = new example.Monster(data); 36 expect(mon.hp, 80); 37 expect(mon.mana, 150); 38 expect(mon.name, 'MyMonster'); 39 expect(mon.pos.x, 1.0); 40 expect(mon.pos.y, 2.0); 41 expect(mon.pos.z, 3.0); 42 expect(mon.pos.test1, 3.0); 43 expect(mon.pos.test2.value, 2.0); 44 expect(mon.pos.test3.a, 5); 45 expect(mon.pos.test3.b, 6); 46 expect(mon.testType.value, example.AnyTypeId.Monster.value); 47 expect(mon.test is example.Monster, true); 48 final monster2 = mon.test as example.Monster; 49 expect(monster2.name, "Fred"); 50 51 expect(mon.inventory.length, 5); 52 expect(mon.inventory.reduce((cur, next) => cur + next), 10); 53 expect(mon.test4.length, 2); 54 expect( 55 mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100); 56 expect(mon.testarrayofstring.length, 2); 57 expect(mon.testarrayofstring[0], "test1"); 58 expect(mon.testarrayofstring[1], "test2"); 59 60 // this will fail if accessing any field fails. 61 expect(mon.toString(), 62 'Monster{pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], color: Color{value: 8}, testType: AnyTypeId{value: 1}, test: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], testarrayofstring: [test1, test2], testarrayoftables: null, enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, testhashs64Fnv1: 7930699090847568257, testhashu64Fnv1: 7930699090847568257, testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, testhashs64Fnv1a: 4898026182817603057, testhashu64Fnv1a: 4898026182817603057, testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], vectorOfLongs: [1, 100, 10000, 1000000, 100000000], vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}'); 63 } 64} 65 66@reflectiveTest 67class BuilderTest { 68 void test_monsterBuilder() { 69 final fbBuilder = new Builder(); 70 final str = fbBuilder.writeString('MyMonster'); 71 72 fbBuilder.writeString('test1'); 73 fbBuilder.writeString('test2'); 74 final testArrayOfString = fbBuilder.endStructVector(2); 75 76 final fred = fbBuilder.writeString('Fred'); 77 78 final List<int> treasure = [0, 1, 2, 3, 4]; 79 final inventory = fbBuilder.writeListUint8(treasure); 80 81 final monBuilder = new example.MonsterBuilder(fbBuilder) 82 ..begin() 83 ..addNameOffset(fred); 84 final mon2 = monBuilder.finish(); 85 86 final testBuilder = new example.TestBuilder(fbBuilder); 87 testBuilder.finish(10, 20); 88 testBuilder.finish(30, 40); 89 final test4 = fbBuilder.endStructVector(2); 90 91 92 monBuilder 93 ..begin() 94 ..addPos( 95 new example.Vec3Builder(fbBuilder).finish( 96 1.0, 97 2.0, 98 3.0, 99 3.0, 100 example.Color.Green, 101 () => testBuilder.finish(5, 6), 102 ), 103 ) 104 ..addHp(80) 105 ..addNameOffset(str) 106 ..addInventoryOffset(inventory) 107 ..addTestType(example.AnyTypeId.Monster) 108 ..addTestOffset(mon2) 109 ..addTest4Offset(test4) 110 ..addTestarrayofstringOffset(testArrayOfString); 111 final mon = monBuilder.finish(); 112 fbBuilder.finish(mon); 113 } 114 115 void test_error_addInt32_withoutStartTable() { 116 Builder builder = new Builder(); 117 expect(() { 118 builder.addInt32(0, 0); 119 }, throwsStateError); 120 } 121 122 void test_error_addOffset_withoutStartTable() { 123 Builder builder = new Builder(); 124 expect(() { 125 builder.addOffset(0, 0); 126 }, throwsStateError); 127 } 128 129 void test_error_endTable_withoutStartTable() { 130 Builder builder = new Builder(); 131 expect(() { 132 builder.endTable(); 133 }, throwsStateError); 134 } 135 136 void test_error_startTable_duringTable() { 137 Builder builder = new Builder(); 138 builder.startTable(); 139 expect(() { 140 builder.startTable(); 141 }, throwsStateError); 142 } 143 144 void test_error_writeString_duringTable() { 145 Builder builder = new Builder(); 146 builder.startTable(); 147 expect(() { 148 builder.writeString('12345'); 149 }, throwsStateError); 150 } 151 152 void test_file_identifier() { 153 Uint8List byteList; 154 { 155 Builder builder = new Builder(initialSize: 0); 156 builder.startTable(); 157 int offset = builder.endTable(); 158 byteList = builder.finish(offset, 'Az~ÿ'); 159 } 160 // Convert byteList to a ByteData so that we can read data from it. 161 ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes); 162 // First 4 bytes are an offset to the table data. 163 int tableDataLoc = byteData.getUint32(0, Endian.little); 164 // Next 4 bytes are the file identifier. 165 expect(byteData.getUint8(4), 65); // 'a' 166 expect(byteData.getUint8(5), 122); // 'z' 167 expect(byteData.getUint8(6), 126); // '~' 168 expect(byteData.getUint8(7), 255); // 'ÿ' 169 // First 4 bytes of the table data are a backwards offset to the vtable. 170 int vTableLoc = tableDataLoc - 171 byteData.getInt32(tableDataLoc, Endian.little); 172 // First 2 bytes of the vtable are the size of the vtable in bytes, which 173 // should be 4. 174 expect(byteData.getUint16(vTableLoc, Endian.little), 4); 175 // Next 2 bytes are the size of the object in bytes (including the vtable 176 // pointer), which should be 4. 177 expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4); 178 } 179 180 void test_low() { 181 Builder builder = new Builder(initialSize: 0); 182 expect((builder..putUint8(1)).lowFinish(), [1]); 183 expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]); 184 expect((builder..putUint8(3)).lowFinish(), 185 [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 186 expect((builder..putUint8(4)).lowFinish(), 187 [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 188 expect((builder..putUint8(5)).lowFinish(), 189 [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 190 expect((builder..putUint32(6)).lowFinish(), 191 [6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 192 } 193 194 void test_table_default() { 195 List<int> byteList; 196 { 197 Builder builder = new Builder(initialSize: 0); 198 builder.startTable(); 199 builder.addInt32(0, 10, 10); 200 builder.addInt32(1, 20, 10); 201 int offset = builder.endTable(); 202 byteList = builder.finish(offset); 203 } 204 // read and verify 205 BufferContext buffer = new BufferContext.fromBytes(byteList); 206 int objectOffset = buffer.derefObject(0); 207 // was not written, so uses the new default value 208 expect( 209 const Int32Reader() 210 .vTableGet(buffer, objectOffset, indexToField(0), 15), 211 15); 212 // has the written value 213 expect( 214 const Int32Reader() 215 .vTableGet(buffer, objectOffset, indexToField(1), 15), 216 20); 217 } 218 219 void test_table_format() { 220 Uint8List byteList; 221 { 222 Builder builder = new Builder(initialSize: 0); 223 builder.startTable(); 224 builder.addInt32(0, 10); 225 builder.addInt32(1, 20); 226 builder.addInt32(2, 30); 227 byteList = builder.finish(builder.endTable()); 228 } 229 // Convert byteList to a ByteData so that we can read data from it. 230 ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes); 231 // First 4 bytes are an offset to the table data. 232 int tableDataLoc = byteData.getUint32(0, Endian.little); 233 // First 4 bytes of the table data are a backwards offset to the vtable. 234 int vTableLoc = tableDataLoc - 235 byteData.getInt32(tableDataLoc, Endian.little); 236 // First 2 bytes of the vtable are the size of the vtable in bytes, which 237 // should be 10. 238 expect(byteData.getUint16(vTableLoc, Endian.little), 10); 239 // Next 2 bytes are the size of the object in bytes (including the vtable 240 // pointer), which should be 16. 241 expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16); 242 // Remaining 6 bytes are the offsets within the object where the ints are 243 // located. 244 for (int i = 0; i < 3; i++) { 245 int offset = 246 byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little); 247 expect(byteData.getInt32(tableDataLoc + offset, Endian.little), 248 10 + 10 * i); 249 } 250 } 251 252 void test_table_string() { 253 String latinString = 'test'; 254 String unicodeString = 'Проба пера'; 255 List<int> byteList; 256 { 257 Builder builder = new Builder(initialSize: 0); 258 int latinStringOffset = builder.writeString(latinString); 259 int unicodeStringOffset = builder.writeString(unicodeString); 260 builder.startTable(); 261 builder.addOffset(0, latinStringOffset); 262 builder.addOffset(1, unicodeStringOffset); 263 int offset = builder.endTable(); 264 byteList = builder.finish(offset); 265 } 266 // read and verify 267 BufferContext buf = new BufferContext.fromBytes(byteList); 268 int objectOffset = buf.derefObject(0); 269 expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)), 270 latinString); 271 expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)), 272 unicodeString); 273 } 274 275 void test_table_types() { 276 List<int> byteList; 277 { 278 Builder builder = new Builder(initialSize: 0); 279 int stringOffset = builder.writeString('12345'); 280 builder.startTable(); 281 builder.addBool(0, true); 282 builder.addInt8(1, 10); 283 builder.addInt32(2, 20); 284 builder.addOffset(3, stringOffset); 285 builder.addInt32(4, 40); 286 builder.addUint32(5, 0x9ABCDEF0); 287 builder.addUint8(6, 0x9A); 288 int offset = builder.endTable(); 289 byteList = builder.finish(offset); 290 } 291 // read and verify 292 BufferContext buf = new BufferContext.fromBytes(byteList); 293 int objectOffset = buf.derefObject(0); 294 expect( 295 const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true); 296 expect( 297 const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10); 298 expect( 299 const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20); 300 expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)), 301 '12345'); 302 expect( 303 const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40); 304 expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)), 305 0x9ABCDEF0); 306 expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)), 307 0x9A); 308 } 309 310 void test_writeList_of_Uint32() { 311 List<int> values = <int>[10, 100, 12345, 0x9abcdef0]; 312 // write 313 List<int> byteList; 314 { 315 Builder builder = new Builder(initialSize: 0); 316 int offset = builder.writeListUint32(values); 317 byteList = builder.finish(offset); 318 } 319 // read and verify 320 BufferContext buf = new BufferContext.fromBytes(byteList); 321 List<int> items = const Uint32ListReader().read(buf, 0); 322 expect(items, hasLength(4)); 323 expect(items, orderedEquals(values)); 324 } 325 326 void test_writeList_ofBool() { 327 void verifyListBooleans(int len, List<int> trueBits) { 328 // write 329 List<int> byteList; 330 { 331 Builder builder = new Builder(initialSize: 0); 332 List<bool> values = new List<bool>.filled(len, false); 333 for (int bit in trueBits) { 334 values[bit] = true; 335 } 336 int offset = builder.writeListBool(values); 337 byteList = builder.finish(offset); 338 } 339 // read and verify 340 BufferContext buf = new BufferContext.fromBytes(byteList); 341 List<bool> items = const BoolListReader().read(buf, 0); 342 expect(items, hasLength(len)); 343 for (int i = 0; i < items.length; i++) { 344 expect(items[i], trueBits.contains(i), reason: 'bit $i of $len'); 345 } 346 } 347 348 verifyListBooleans(0, <int>[]); 349 verifyListBooleans(1, <int>[]); 350 verifyListBooleans(1, <int>[0]); 351 verifyListBooleans(31, <int>[0, 1]); 352 verifyListBooleans(31, <int>[1, 2, 24, 25, 30]); 353 verifyListBooleans(31, <int>[0, 30]); 354 verifyListBooleans(32, <int>[1, 2, 24, 25, 31]); 355 verifyListBooleans(33, <int>[1, 2, 24, 25, 32]); 356 verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]); 357 verifyListBooleans(63, <int>[]); 358 verifyListBooleans(63, <int>[0, 1, 2, 61, 62]); 359 verifyListBooleans(63, new List<int>.generate(63, (i) => i)); 360 verifyListBooleans(64, <int>[]); 361 verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]); 362 verifyListBooleans(64, <int>[1, 2, 62]); 363 verifyListBooleans(64, <int>[0, 1, 2, 63]); 364 verifyListBooleans(64, new List<int>.generate(64, (i) => i)); 365 verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]); 366 } 367 368 void test_writeList_ofInt32() { 369 List<int> byteList; 370 { 371 Builder builder = new Builder(initialSize: 0); 372 int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]); 373 byteList = builder.finish(offset); 374 } 375 // read and verify 376 BufferContext buf = new BufferContext.fromBytes(byteList); 377 List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0); 378 expect(items, hasLength(5)); 379 expect(items, orderedEquals(<int>[1, 2, 3, 4, 5])); 380 } 381 382 void test_writeList_ofFloat64() { 383 List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13]; 384 // write 385 List<int> byteList; 386 { 387 Builder builder = new Builder(initialSize: 0); 388 int offset = builder.writeListFloat64(values); 389 byteList = builder.finish(offset); 390 } 391 392 // read and verify 393 BufferContext buf = new BufferContext.fromBytes(byteList); 394 List<double> items = const Float64ListReader().read(buf, 0); 395 396 expect(items, hasLength(values.length)); 397 for (int i = 0; i < values.length; i++) { 398 expect(values[i], closeTo(items[i], .001)); 399 } 400 } 401 402 void test_writeList_ofFloat32() { 403 List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13]; 404 // write 405 List<int> byteList; 406 { 407 Builder builder = new Builder(initialSize: 0); 408 int offset = builder.writeListFloat32(values); 409 byteList = builder.finish(offset); 410 } 411 // read and verify 412 BufferContext buf = new BufferContext.fromBytes(byteList); 413 List<double> items = const Float32ListReader().read(buf, 0); 414 expect(items, hasLength(5)); 415 for (int i = 0; i < values.length; i++) { 416 expect(values[i], closeTo(items[i], .001)); 417 } 418 } 419 420 void test_writeList_ofObjects() { 421 List<int> byteList; 422 { 423 Builder builder = new Builder(initialSize: 0); 424 // write the object #1 425 int object1; 426 { 427 builder.startTable(); 428 builder.addInt32(0, 10); 429 builder.addInt32(1, 20); 430 object1 = builder.endTable(); 431 } 432 // write the object #1 433 int object2; 434 { 435 builder.startTable(); 436 builder.addInt32(0, 100); 437 builder.addInt32(1, 200); 438 object2 = builder.endTable(); 439 } 440 // write the list 441 int offset = builder.writeList([object1, object2]); 442 byteList = builder.finish(offset); 443 } 444 // read and verify 445 BufferContext buf = new BufferContext.fromBytes(byteList); 446 List<TestPointImpl> items = 447 const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0); 448 expect(items, hasLength(2)); 449 expect(items[0].x, 10); 450 expect(items[0].y, 20); 451 expect(items[1].x, 100); 452 expect(items[1].y, 200); 453 } 454 455 void test_writeList_ofStrings_asRoot() { 456 List<int> byteList; 457 { 458 Builder builder = new Builder(initialSize: 0); 459 int str1 = builder.writeString('12345'); 460 int str2 = builder.writeString('ABC'); 461 int offset = builder.writeList([str1, str2]); 462 byteList = builder.finish(offset); 463 } 464 // read and verify 465 BufferContext buf = new BufferContext.fromBytes(byteList); 466 List<String> items = 467 const ListReader<String>(const StringReader()).read(buf, 0); 468 expect(items, hasLength(2)); 469 expect(items, contains('12345')); 470 expect(items, contains('ABC')); 471 } 472 473 void test_writeList_ofStrings_inObject() { 474 List<int> byteList; 475 { 476 Builder builder = new Builder(initialSize: 0); 477 int listOffset = builder.writeList( 478 [builder.writeString('12345'), builder.writeString('ABC')]); 479 builder.startTable(); 480 builder.addOffset(0, listOffset); 481 int offset = builder.endTable(); 482 byteList = builder.finish(offset); 483 } 484 // read and verify 485 BufferContext buf = new BufferContext.fromBytes(byteList); 486 StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0); 487 List<String> items = reader.items; 488 expect(items, hasLength(2)); 489 expect(items, contains('12345')); 490 expect(items, contains('ABC')); 491 } 492 493 void test_writeList_ofUint32() { 494 List<int> byteList; 495 { 496 Builder builder = new Builder(initialSize: 0); 497 int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]); 498 byteList = builder.finish(offset); 499 } 500 // read and verify 501 BufferContext buf = new BufferContext.fromBytes(byteList); 502 List<int> items = const Uint32ListReader().read(buf, 0); 503 expect(items, hasLength(3)); 504 expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0])); 505 } 506 507 void test_writeList_ofUint16() { 508 List<int> byteList; 509 { 510 Builder builder = new Builder(initialSize: 0); 511 int offset = builder.writeListUint16(<int>[1, 2, 60000]); 512 byteList = builder.finish(offset); 513 } 514 // read and verify 515 BufferContext buf = new BufferContext.fromBytes(byteList); 516 List<int> items = const Uint16ListReader().read(buf, 0); 517 expect(items, hasLength(3)); 518 expect(items, orderedEquals(<int>[1, 2, 60000])); 519 } 520 521 void test_writeList_ofUint8() { 522 List<int> byteList; 523 { 524 Builder builder = new Builder(initialSize: 0); 525 int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]); 526 byteList = builder.finish(offset); 527 } 528 // read and verify 529 BufferContext buf = new BufferContext.fromBytes(byteList); 530 List<int> items = const Uint8ListReader().read(buf, 0); 531 expect(items, hasLength(5)); 532 expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A])); 533 } 534} 535 536class StringListWrapperImpl { 537 final BufferContext bp; 538 final int offset; 539 540 StringListWrapperImpl(this.bp, this.offset); 541 542 List<String> get items => const ListReader<String>(const StringReader()) 543 .vTableGet(bp, offset, indexToField(0)); 544} 545 546class StringListWrapperReader extends TableReader<StringListWrapperImpl> { 547 const StringListWrapperReader(); 548 549 @override 550 StringListWrapperImpl createObject(BufferContext object, int offset) { 551 return new StringListWrapperImpl(object, offset); 552 } 553} 554 555class TestPointImpl { 556 final BufferContext bp; 557 final int offset; 558 559 TestPointImpl(this.bp, this.offset); 560 561 int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0); 562 563 int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0); 564} 565 566class TestPointReader extends TableReader<TestPointImpl> { 567 const TestPointReader(); 568 569 @override 570 TestPointImpl createObject(BufferContext object, int offset) { 571 return new TestPointImpl(object, offset); 572 } 573} 574