Squashed 'third_party/flatbuffers/' changes from 338393f85..e5f331db9
e5f331db9 [TS] Add single-file ts codegen & bazel rule for typescript (#7161)
2f84c6038 Apply Namer to Go code gen (#7150)
d64839651 [Lobster] file_identifier support
777e78d8d [Lobster] support unsigned integer reads
4016c549d Apply Namer to Python code gen (#7146)
40827b21b Fix missing 'break' (#7151)
65a10b6e3 Implement a config based name manager and use it in Rust codegen (#7144)
8db2fef3f [TS] Escape keywords in typescript object names (#7137)
9ed132304 Fix 64-bit numeric enum values in typescript (#7135)
1a4c40566 updated npm to 2.0.6
318594e4b prevent name clash (#7133)
3d903302c [Rust] Add length checks to arrays and vectors. (#7130)
c9571d989 Replaced ToDasherCase with ConvertCase (#7131)
3694b830a Use ConvertCase instead of Make{Upper,Lower,Snake} implementations (#7127)
0471fa807 remove stall reference to version
914344ea9 some minor help edits
b40266c56 Use target_compile_features to target C++11 (#7122)
8a9303d46 update proto tests with alaised enum (#7121)
30c4bf47f Trigger fuzzing CI only on relevant changes (#7120)
46ce45601 remove auto generate code from cmakelists (#7119)
433312c55 add the missing checkNullConditionnal code in the "GenObjApi" function when the field is scalar optional (#7114)
9c52ec374 Add deps attribute to flatbuffer_cc_library (#7107)
70e2f49bf fixed string-json -> strict-json typo
5ac0367ed [TS] Fix generation of reserved words in object api (#7106) (#7115)
5d101afb5 Fix minor typo in WhitePaper.md (#7108)
06f4af11b Go optional scalars (#7104)
57e338f81 explicitly use windows-2019 to unblock ci (#7105)
615616cb5 Change Rust generated file defaults (#7101)
3413c3300 Fixed FlexBuffers verifier fuzzer timing out
69f5660a4 Fixed Parser not checking size of union types vector
d5add9fca Fixed FlexBuffers ToString unquoted non-ident keys
15df50eb7 Remove @ExperimentalUnsignedTypes annotation from kotlin code generator. (#7092)
a94132a45 Swift FlatBufferBuilder.sizedByteArray to ByteBuffer.toArray() (#7093)
48befb6be [TS] Refactor away circular ref (#7099)
b30069133 Add reflection support for python (#7026)
faadbc10e Add CreateVector overload to accept array like (#7095)
ed6ae8d32 explicitly defined std::allocator (#7094)
e910bddbc [JS] Add ".js" suffix to all import statements to generate a browser compatible mjs version. (#7086)
c85fb690f Add Parsing Completed function for Rust (#7084)
c1daa6ba0 rust: Bump thiserror version and remove git dependency (#7080)
4c71c7b02 replace framework include of flatbuffers (#7079)
f5664d33f fix go_test implement error (#7012)
39c8a19ce fixed comparator for native_inline (#7076)
826193ff6 skip generating reflection.fbs in generate_scripts (#7077)
fd0d1ed92 update C++ generator to emit scoped enums in vector of unions (#7075)
424988f30 replaced removed xml tag
b2550dbaa removed BSD-3-Clause license and Zlib licenses (#7073)
a2b238960 Fixed default value of bool in struct for Swift (#7072)
619b78437 one last dart omit local (#7070)
68a766154 more omit type annotations for dart local variables (#7069)
7dac9961f omit type annotations for dart local variables (#7067)
c65c389c6 add xmlns to .Net (#7066)
6446dcf3d Updates swift gen licence for grpc code (#7063)
e090d8da1 Fixed long cast to int in flexbufferbuilder.java (#7059)
bc901436d clang format on codebase (#7058)
240be9b5a attempt to remove appveyor (#7056)
bc366a7f9 Provide a short help text and default in error case (#6992)
14b19d446 Use FindPython3 (#7055)
9e6f17b94 remove BIICODE
c3801ad37 Update readme.md
4f3b24db0 Fixes a bug where bools arent being nil when marked optional (#7051)
1d294a31b Implement Serialize on generated rust types (#7022)
dd8fccfb1 Cmake 3.16 de-facto minimum version (#7049)
7089c9ecd Convert flatbuffers_version_string to inline function (#7046)
43203984f [C++] Support C++ object copies and moves (#5988)
5993338ee [ts] Builder incorrectly serializing empty strings (#7047)
19920db39 Include a SizePrefixed..HasIdentifier for c++. (#6871)
dbbaeac85 Use `${PYTHON_EXECUTABLE}` instead of `py` in cmake (#7042)
028f0fde6 'flattest': Add --test_path option (#7041)
87343631b Added support for clang-cl on windows (CMake) (#7038)
1fbfaf5c5 Fix/cmake build grpc (#7028)
4421375bb Add FlatBuffers::FlatBuffers interface, needed for FetchContent_Declare (#7023)
162ad7a37 Fix comment with line orders - Rust should be last. (#7037)
a0a6c3f8c Use actions/checkout@v2, which fixes security vulnerability. (#7036)
a2d38fbb9 Add --warnings-as-errors to flatc compiler. (#7034)
9ef1524d3 Emit include for bfbs-gen-embed (#7031)
0c9de0352 Upgraded GRPC version to 1.42.0 (#7033)
a783bc926 chore: dart 2.0.5 release changes (#6983)
aff818ceb rust: Allow for usage in no_std environment (#6989)
d7b75417f Make flatbuffer builder deterministic (#6993)
a42e89897 Added verifier alignment checking to table fields (#7018)
96cc2f3ee BuildFlatBuffers.cmake: fix arguments not passed properly to flatc (#7013)
3250a1f8d Add initial C# vector of unions support to the documentation. (#6880)
ace4a37f2 [TS/JS] BigInt implementation (#6998)
f28c2b293 Avoid implicit conversion from float to double. (#7003)
96f3cf690 Rearrange #include directives to pass to compilation with a particular DSP toolchain (#7000)
b3edfdbfb Reverting grpc generated file suffix (#6995)
b8aaccee8 Disable parsing of nested_flatbuffers as bytes by default
2dc8ae774 Enable OSS-Fuzz on CI
5b0d49112 Updated FlexBuffers fuzzer
d8b7041d7 Added alignment checking to FlexBuffers verifier
5a0c3366c FlexBuffers verifier additionally checks for nesting
f8148b8da Made FlexBuffers reuse tracker track types
a22b1b626 Prevent shadow with _{{FIELD_NAME}} (#6991)
4264daadd FlexBuffers fuzzer fixes
3cbc120a0 Refractor Flatc Options (#6987)
8dcd2682c [CMake] Add option for disable universal on OSX (#6990)
b78002ff3 Validate C# json/object-api options (#6985)
c555ee8fa Add .NET test to github workflows (#6982)
b92bb0584 [CMake]: Fix version in pkgconfig file (#6986)
956d11569 re-enabled FlexBuffer JSON in fuzzer
e367ca32a Verifier for FlexBuffers (#6977)
705f27f6e [CMake]: Fix python command for mingw environment (#6984)
5fc87f4c4 Enable --gen-onefile in Python (#6953)
11749095a Make idl_parser deterministic (#6976)
d0cede9c9 Bumping to Version 2.0.5 (#6967)
fcc2bee0b Fix typo in variable name (#6973)
e08da4dea remove Appveyor's Vs2010 and 13 builds (#6969)
18538c401 [TS] Fix reserved words as arguments (#6955) (#6956)
e57f4ab2d Update stale bot version and provide away to exempt issues with the not-stale label (#6968)
deed68db5 missing generated files (#6966)
061d61f3f Lua Generator using IR. (#6940)
cffe0c454 FixedTypedVector: add const to ElementType() and size() (#6965)
fadd40e40 Have grpc include file with correct filename-suffix given to flatc (#6954)
e47dc0e46 Removed test/generate_code.{sh|bat} (#6873)
5c5475479 switched to windows-lastest, removed deadcode (#6948)
4f7f6dc30 Restore FlatBufferBuilder::kFileIdentifierLength. (#6960)
0fadaf391 Enable verifier on nested_flatbuffers
4d0e9a870 Turn off nested FlatBuffers/FlexBuffers for the fuzzer
c05f6783a invalid conditional running genrate_code.py (#6952)
a14f4052c rust: remove needless borrow (#6922)
9e4ca857b Vector Downward GetSize optimization (#6925)
a2b99084b Fix flexbuffers clang-analyzer warning (#6947)
85b4effac test: fix undefined order of functio parameters. (#6946)
790f41154 [cmake] Fix getting version info from tags during the build (#6936)
e89de4411 clang-all (#6941)
256ab3798 WIP: Dart release 2.0 (#6927)
a59288a01 Add benchmarks to Linux CI (#6928)
587bbd49a [C++] Fix compile failure on Object API union construction for struct member (#6923)
a9c341545 Fix integer overflow warnings
8aa18b629 fixed cmp0048 error (#6932)
d727579b6 fuzzers: fix typo in file path (#6931)
97a30171c Added Raw C++ benchmarks (#6924)
0989fc5e5 Added Google benchmarks (and gtests) (#6920)
927175ea2 [Java] lookup by byteArray is giving back wrong entry (#6915)
6748c373b Removal of support for FLATBUFFERS_CPP98_STL (#6918)
3fab0c6ee move [[ ]] to calling sites (#6914)
6c8c29155 [C++] Split flatbuffers.h into separate files (#6868)
fd4ff23da Keep methods with struct name and switch them to default (#6879)
f8b69e330 [Python] Verify EnumDef is not generated in GenUnionCreator (#6903)
c0394bb09 Support `--conform` for vector of unions (#6883)
8433eb108 Typo fixes in comments of flatbuffers.h and flexbuffers.h (#6901)
f2f9380c8 [Java] Prevent generation of enum names when underlying type is long (#6781) (#6895)
e672dabfe [C++] Fix memory leak when using grpc (#6896) (#6897)
9a4ca2764 Output errors / warnings on stderr instead of stdout (#6881)
4c7a9c10d Adds JSON encoding to swift (#6874)
38295a187 [Kotlin] Fix missing escape for struct construction statements (#6877)
31bb0b972 add working directory (#6878)
45e5642e9 Default Arguments for Mutators C++ [Updated] (#6872)
a592f4c89 [Cmake] Add a post build command after flatc to run the new generate_code.py script. (#6866)
b9d43a557 dart - add Packable interface (#6846)
2ece9e25b Bumped package.json to 2.0.4
2dd212637 Fix linker errors on (Free|Open)BSD. (#6860)
f63c130c2 Improves documentation, and adding DocC (#6784)
e2b26ee19 Make and generate_code.sh generate same outputs (#6855)
9d686bf43 Include subdirectories in published npm package (#6850)
1d26daff3 Use ArrayBuffer type for JS flexbuffer's toObject (#6851)
e72e18d9f feat(build): compile "universal" libraries and executables for Mac (#6852)
354d97f6d fixed errant itemgroup element in C# test project (#6854)
6f7a57eaa [C#] Using 'global::' as qualifying_start_ within BaseGenerator (#6767)
90baa1444 Dart: binary lists (typed_data) (#6839)
0a3b017f0 Delete IDLOptions::lang (#6841)
47d35f105 BugFix: Optional enum when it is null (#6835)
8fb8c2ce1 [C#] Use @ for keyword escaping (#6834)
1d063d87c [C++] Let builder accept custom-alloc std::vector (#6814)
338331b55 Changes to support binary schema file loading and parsing (flatc) (#6823)
156a30c75 Move Apple-specific build flags to Clang section (#6802)
550d2f904 Issue error if jsonschema has no root type defined #6821 (#6831)
c3a38242e Fix typos in docs (#6829)
74c3d7eba [C++] Add mutable version of LookupByKey and test (#6826)
db6eae5c4 Add html and latex to gitignore (#6819)
0e9d79c35 [Java] Avoid casting ByteBuffer to Buffer (#6785)
b20c4d3aa [C++] Add GetMutableSizePrefixedRoot and generate GetMutableSizePrefixedXxx functions (#6815)
ae145293c flattests_cpp17 doesn't compile with Visual Studio 2017: warning C4100: 'indent': unreferenced formal parameter (#6811)
e3c76a5cd Dart lints (#6808)
4b9123baf fix parser string=null (#6810)
f89e0b1a6 Refactor idl_gen_rust and Rust generated code to use consistent whitespace (#6809)
273f6084e Fix Rust keyword inconsistency (#6794)
4a0879458 [C#] Remove superfluous semicolon in C# structs (#6791)
d6f51ea16 fix ptr in flatbuffers cpp tutorial (#6787)
067dce6e7 [C#] Handle keywords (#6775)
2ca5f0e72 [C#] Respect command line parameter for file name extension and suffix (#6779)
f20d2253a update Java version to 2.0.3
390d438e2 [Kotlin] Fix CI by changing compiler to Java 11 (#6783)
6fb2c90d9 avoiding even more NoSuchMethod exceptions (#6729)
a7b527d94 java: Use maven profile to target Java 8 bytecode (#6764)
5d77820b3 [C++] Using calculated fields_number for field_names size (#6769)
909ce970a [C++] Use UnPackTo instead of UnPack if pointer exists (#6725)
35e2cac6e Store vtables sorted in Rust builder (#6765)
c39fc9dd9 [C++] Use nullptr instead of 0 in generated headers (#6762)
775c6567d [C++] Fix compiler warning -Wredundant-parens in clang (#6761)
97d9527f6 Dart 2.0 release prep (#6759)
e01205466 [C++] Use proper gRPC C++ API when using MemoryBuffer Slice (#6756)
5235133f3 Dart - make ascii optimization optional in StringReader, same as in writeString() (#6758)
c871df770 Dart - change table building to assert() instead of exceptions (#6754)
a6eeeb3b9 Dart - inline small functions to increase performance (#6755)
3dd02144d [C#] Fix field name struct name collision (#6744) (#6757)
e77926f0e [C#] Add Union Constructor Utility for ObjectAPI. (#6105)
ac2348202 Dart - fixup writeString() return type after previous merges (#6753)
8be8a0a71 [C++] Fix union type handling on object api in C++17 (#6745)
12e341e4f Rework how Rust generated files are laid out (#6731)
c36672d80 Dart - optimize writeString for ASCII (#6736)
2bfc8e9f0 Dart - make writeString() argument non-nullable (#6737)
674a9f2aa fix lints in rust tests (#6743)
016e6aa13 Add a split on ':' to build_defs.bzl (#6742)
65700441d Dart - make vTable fixed size (expect the number of fields when creating) (#6735)
dd5bb55ca Dart - make vTable deduplication optional (#6734)
e8423da1b Dart - regenerate example after recent flatc changes (#6733)
0980e39c9 flexbuffers: Add variant of Blob() that takes a key (#6730)
e73fab27d Dart - store empty vectors instead of NULL (#6728)
92ae532e4 Dart - finish/lowFinish/buffer changes (#6712)
7482b25f8 Remove ubuntu1604 from presubmit.yml (#6715)
3f77dc9a0 Dart - unpack() must use eager list reader (#6723)
838c93b84 Dart - fix flex-builder compilation error (#6722)
089f48a4a Dart - make sure added padding is zeroed, same as in C++ (#6716)
bf3470c16 Fix UB in CreateVectorOfStructs in case of an empty vector: avoid calling memcpy in this case (#6726)
8f8196e13 Fix 6348 (#6717)
8ab35b2a5 Dart - add custom allocator support (#6711)
c0ba2870c Fix typo in docu (#6714)
22498cf3a [C++] add make_span for Array<T,N> (#6663)
bd37e67ac [C++] Fix a -Wdeprecated-copy warning. (#6708)
a6ee33557 Dart null safety (#6696)
71d43f3be Make --bfbs-filenames default to location of first schema file. (#6705)
c8db1ca5d Jsonschema add prop comments (#6617)
962751a6e Improve generated comparisons for tables (#6486)
06fd6d640 Replace filenames in reflection with filenames+includes. (#6703)
acce4ac3f Fix incorrect assertion usage. (#6702)
8fd7861b7 Fix warning about deprecated module: imp (#6362)
c58ae9422 Add the file a symbol is declared in to Reflection (#6613)
2cf7bb796 Intermediate Representation docs (#6685)
4e3a66c14 Dart object API (#6682)
d959e2320 dart - change Builder.reset() to reuse an existing buffer (#6661)
a9fb54088 use improved versioning (#6691)
337eb8b8f update docs - structs can't be roots (#6690)
6415ef05d [Python] [Codegen] Fixes nested structs with underscore names (#6686)
f069396d1 [C++] flatc --cpp-field-case-style option to permit camel-case field names in C++ (#6669)
021177af0 Fix snap version formatting (#6683)
e1e9f9373 [C++/grpc] added hiding of unused variables in the generated code (#6677)
15110094e Fix GitHub Actions CI gcc/clang versions
093badb0a Use unoptimized path for ReadUInt64 for win32 build as the optimized path crashes. (#6681)
752c7b576 avoiding more NoSuchMethod exceptions (#6671)
7c3e267e1 [Java] ObjectAPI implementation (#6521) (#6582)
baaffbaed npm update to 2.0.3 and script fix
4cb3f222b [TS] Fix module reference in package.json (#6676)
eabdbda75 [TS] Generate entry point module (#6674)
bec23700f Prepare for Java 2.0.1 release
12f2eedad Update CI to GCC/Clang 11
221eeb231 Fix typo in C++ doc (#6664)
813d3632e avoiding NoSuchMethod exception (#6658)
d84bccb0c Removed most heap allocations in builder (#6662)
b4e67f9bf Dart test fix (#6660)
54c11932f [Java] Flexbuffers - Negative signed object length (#6651)
fbcb3c423 [TS/JS] Updates the grpc (#6654)
8937dcfd7 Updates go lang support to allow other languages to communicate with it (#6653)
512d5a689 Update readme.md to point to security policy
a92cb5dd7 Create Security.md
d151dcbb9 Revert "[C++] Removed most heap allocations in builder (#6620)" (#6659)
f1884c66f Fix gRPC test to use EndVector without specifying the length. (#6646)
72730ecd8 [C++] Removed most heap allocations in builder (#6620)
fe2bc2b0a Added README for Rust Flatbuffers (before publishing v=2.0) (#6652)
4867c9456 Fixed generation of c++ code with flags (#6637)
ef0eb3701 Ran clang-format-all.sh. Removed default --style=file parameter (#6639)
f83ee1af5 [idl_parser] Check structs and enums do not clash in a namespace (#6562)
a5175c513 Implements verifier and code gen for swift (#6373)
04b10f5a3 Deprecate EnumVal.object (#6612)
c121c0345 Fixed Java gRPC version number dependency
8fd10606c Implement Serialize for flexbuffer::Reader (#6635)
a1730fcea [Swift] Updated cocoapods to 2.0.0 (#6634)
a9a295fec More missing version changes
5c01ad387 Dart generated code update
42ca1b914 Swift/Kotlin generated code version updates
6ed780dbd C++/Rust version changes
3412fab8e C#/Java generated code version updates
8a7d013f8 Updated main version numbers to 2.0
170af5978 [Go] Add missing namespace when using Object API (#6633)
c8c16de16 Fix reverse iterators for Vector and Array (#6626)
4525cd9c5 [Lua] manipulate byte array as string (#6624)
47361baf6 [C++] Fix union copy constructor to work with nested structs (#6552) (#6607)
8a582883a Updates swift generated monster sample file (#6616)
a4bb8f0c2 [Lua] Avoid infinite loop when creating empty string (#6614)
82aed82b8 Added support for Lua 5.1, 5.2 and 5.4 (#6606)
60ff76630 [TS] Remove wrong and obsolete NS prefix use (#6604)
a27c7d809 Fixed LuaJIT when not compiled with COMPAT mode (#6605)
363220823 removed unneeded type prefixing (#6601)
6b44c605b Bump Rust to 0.9.0 (#6610)
d3cd78a87 [Lua] Add LuaJIT support (#6584)
8fa3dfdb5 Introduce new_from_vec in Rust (also fix formatting) (#6599)
29379e8e4 fix typo in CppUsage.md (#6595)
14725d6c3 [Lua] GetRootAs can accept strings. Made Luatest Benchmarks optional (#6593)
16836ff95 Add advance feature indicators to reflection (#6546)
c87179e73 Rust Remove SafeSliceAccess for Arrays, and fix miri. (#6592)
c24031c36 Mark endian_scalar as unsafe. (#6588)
4ccc52c7a [swift] Implements union strings (#6589)
b82fe0738 [Rust] Fix small mistyping (#6585)
1e7f6c8c7 [TS] Commit the generated tests code (#6579)
84714b109 chore: ensure bash is used to generate code (#6577)
1045d7dd4 [Lua] Fix EnforceNumberAndPack for bool type (#6576)
0c7777596 [TS] Remove duplicated build-ts ci (#6575)
c43ba1752 [Rust] Specify Minimum Supported Rust Version (#6573)
da3bb64ef [Rust] Add support for fixed size arrays (#6548)
151900ba9 [Kotlin][FlexBuffers] Add support for Kotlin-iOS (#6564)
c012f29f9 silenced clippy warning (#6565)
df2df21ec [Kotlin] Bump kotlinx.benchmark dependency to 0.3.0 (#6560)
408e4db4a [TS] Add Build TS to CI jobs (#6524)
4d2364f34 [Kotlin][FlexBuffers] Add support for Kotlin-JS (#6554)
261cf3b20 Default-empty vectors of enums (#6505)
cd67261bb [CI] fixes buildkite (#6544)
1aa0c2f6a Limit formatter to pull requests only (#6540)
4133a39df Rust structz (#6539)
1c26d2a1a [Kotlin][FlexBuffers] JSON support for Flexbuffers (#6417)
276b1bc34 [grpc] Support latest version of grpc PoC (#6338)
124654ffc fixed packing structs (#6530)
3b7d1e86b [GO] Tries to add go format to the CI (#6518)
78f0c0d1d [C++] #6501 - Problem when mapping a native type multiple times (#6514)
c992eafb5 [fuzzer] Add `monster_debug` target (#6513)
ef8dd7792 [Swift] Removes allman rule (#6519)
69b329fc8 [flexbuffers, json] Parse `nan` and `inf` (#6512)
6543ba529 fixed packing structs in nested buffers (#6509)
0e453ac35 [idl_parser] Add kTokenNumericConstant token (#6432)
e9b4ae69d Remove `flatbuffers.pc` from the repository (#6508)
fc4fffea4 Bump grpc to 1.0.0 (#6507)
b240ab704 Move Traits struct and Create method out of --cpp-static-reflection. (#6503)
9a4f1f434 Disable x64-specific optimizations for ARM64EC ReadInt64 (#6506)
fac64918d Add --cpp-static-reflection to generate_code.bat. (#6502)
a69815f72 [C++17] Add compile-time reflection for fields. (#6324)
4033ff589 fixed invalid TS call and added test files (#6495)
a08357251 disable clippy (#6494)
5319dedb1 [idl_parser, JSON] Disable parsing of JSON for incomplete schemes (#6493)
bd4e0b30a [idl_parser] Track included files by hash (#6434)
bf9061200 fix for noUncheckedIndexedAccess in ts (#6474)
8142fedd1 Working on a python example plus fixing python grpc code (#6456)
c0be1cb7a [rust] Remove debug code (#6475)
8cccdfba5 Revert "[C#] Fix truncated ArraySegment<byte> if elementSize != 1 (#6462)" (#6488)
cbbbaa61b [C#] Fix truncated ArraySegment<byte> if elementSize != 1 (#6462)
ffc2ef77c [CI] Adds Code Generation tests on Github Actions (#6482)
1da6f4f18 [CMake] generate pkg-config flatbuffers.pc file (#6455)
b5da526e6 [Swift] Moves grpc example to grpc/examples (#6479)
3b5365762 [TS] Moves grpc code to examples folder (#6476)
e2f5438ac Fixes grammer (#6477)
5e3613f73 Fix sample_binary.py to use latest EndVector without a size. (#6478)
e6b911d40 updated JS docs to reflect current status (#6436)
0c7ae5816 [Go] Working on a go example plus fixing go grpc code (#6448)
ae603b977 [Swift] adds support for default vectors and strings (#6461)
7f47718b6 Update Building.md (#6473)
54dc09e8a GetUOffsetT must get value by GetUint32 not GetInt32 (#6072)
334c6be49 Fix a typo in Swift codegen (#6470)
4174c10e7 [rust] Genericize flexbuffer reader (#6450)
a20f606c2 [Swift] Renaming protocols (#6469)
a72a20827 Update swift docs (#6460)
86401e078 Default strings and vectors: Parser + Rust support (#6421)
6af37e672 [CMake] Renames BUILD files (#6457)
1b88655b0 [Build, cmake] Add -Werror override option (#6429)
0b15916e5 [C++]Fix extra char generation for byte type during json schema generation (#6276)
60eed0ca6 Updating working code (#6441)
0f83367f5 JSON schema - tailing double quotes for maximum (#6452)
fee095410 [idl_parser] Validate `force_align` on all possible paths (#6430)
6f3e45eca Implement Rust object API defaults (#6444)
815d3e820 Upgrade swift grpc to alpha 24 (#6439)
76e7a0ff5 [fuzzer] Limit parser_fuzzer execution time (#6431)
6d91096a2 This commit contains the initial implementation of Flexbuffers in Kotlin. The code was ported based (#6387)
13d9e3585 Better python generated code naming (#6336)
6effe431b Rust: remove inner attributes (#6410)
efcbdc769 [Rust] Ensure unions are referenced with the correct path (#6422)
e581013e3 Refactor FieldDef to model presense as an enum rather than 2 bools. (#6420)
0984d4328 [c++] Apply NativeName before WrapInNameSpace in idl_gen_cpp.cpp (#6419)
786f69b24 Formats cpp code (#6349)
1da0a2dfa Rust Object API (#6070)
796ed68fa Clarify that (Flat|Flex)Buffers do not deduplicate vector elements (#6415)
7b1ee31d8 Clarify that FlatBuffers unions do not support scalars (#6416)
4aff1198d Explain how FlatBuffers encodes unions (#6414)
ad3a729f9 dart Builder - expose finished buffer size (#6403)
52e217706 Remove invalid claim that Protocol Buffers does not support unions (#6413)
760c65755 [TS/JS] New gen TS code gen (#6302)
75c859e98 [idl_parser] Improve symbols lookup thru parent namespaces (#6407)
91b0958c4 Search for includes in the directory containg the current file (#6371)
8008dde11 Upgrade Rust dependencies (#6406)
c81cf8249 [TS/JS] New gen TS code gen prequel to preserve history (#6404)
8573108bb Unset FieldDef.optional if its key (#6402)
7abe612b5 [fuzzer] Fix the binary schema loading in the monster_fuzzer (#6396)
408cf5802 Fix Rust UB problems (#6393)
39e115fdb Define Vector::value_type for STL compatibility (#6394)
85719669c [fuzzer] Debug the monster_tets.bfbs on clusterfuzz server (#6392)
809fe49c7 Fix up scripts, fix generated enum value for strong mode, regenerate files (#6389)
41253e574 [go] tests/GoTest.sh: Fix flags.Parse location to work on new go SDKs. (#6388)
08d2ce844 fix Dart Builder._writeString() - always write trailing zero byte (#6390)
a15a8d930 fix Dart Builder.reset() - clear vTables (#6386)
83ce29cc2 [C++, JSON] Fix nullptr access when reading a key with a default value. (#6375)
4363c1d2c Fix generated EndVector. (#6385)
1bf1ec027 Implements type promotion for Java enum (#6382)
080097653 Delete label_notify.yml
795408115 Disabled PHP CI (#6381)
46545e627 fixed warnings (#6355)
0168178a1 Fix multiple fbs code generation failure (#6365)
82836a62b [idl_parser] Improve stack overflow protection (#6364)
e7430bbeb [idl_parser] Check the range of explicitly set field's id value (#6363)
24dd85fd2 Generate code to encode and decode nested flatbuffers in Python. (#6354)
57f68e289 [Rust] Shared String (#6367)
44cf2bde1 Updates license date to 2021 (#6378)
be37d4da1 include_prefix support for rust (#6330)
4e79d129c [Swift] Rebuild the way swift handles structs from scratch (#6326)
05192553f Fix typos in usage/comments; Make rust generator respect to --filenam… (#6342)
f2511d7d4 Renaming infinity variables in test.cpp (#6340)
f8b203c9c Add vectorNumElements attribute to Builder for simpler vector creation. (#6328)
8ab7c7e2c [CI] Adds formatter to CI (#6272)
7e0039028 Fix Max CI build path (#6333)
65c415911 Generate nullable properties in C# object-based API for optional scalars. (without -gen-mutable) (#6273)
a9e91116d [Python] Commit some orphan python genfile diffs. (#6325)
80a745d9b Fixed missing ending quotes in labeller (#6327)
9fca5e4f4 Add flatc option to inhibit all warnings #6005 (#6301)
92a806b4e [fuzzer] Rename fuzzing dictionaries for `oss-fuzz` (#6318)
9c9baf6d5 bumprust (#6322)
aafc5dc95 Set default initialSize for Builder to 0 (#6310)
442949bc1 Rust Flatbuffers Verifier (#6269)
9064072e8 Version message should be a "STATUS" to avoid going to stderr. (#6316)
fd4c1b5ff Replace std::string and const char* CreateSharedString with string_view (#6315)
bc7eb8ade [fuzzer] Fix mistakes in the `parser` and `scalar` fuzzers. (#6314)
fc960f367 Add default to offset param of Python generated GetRootAs (#6312)
f437f0f7e [fuzzer] Fix loading of schema in monster_fuzzer (#6308)
7f33cf682 [C++] Switch `flatc` to `--cpp-std c++11` C++ code generator (#6306)
8d9eae9ac [idl_parser] Unify parsing of NaN values read from .fbs and .json files (#6296)
2046bffa4 Moved various language tests from AppVeyor to GitHub Actions (#6300)
git-subtree-dir: third_party/flatbuffers
git-subtree-split: e5f331db998a808f78cf5a4880e6f5d0a321c4d0
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
Change-Id: I37f8aaf007fc86226cfa250169a87807afa64a78
diff --git a/swift/FlatBuffers.podspec b/swift/FlatBuffers.podspec
index b106b4c..0119529 100644
--- a/swift/FlatBuffers.podspec
+++ b/swift/FlatBuffers.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FlatBuffers'
- s.version = '0.8.1'
+ s.version = '2.0.0'
s.summary = 'FlatBuffers: Memory Efficient Serialization Library'
s.description = "FlatBuffers is a cross platform serialization library architected for
diff --git a/swift/Package.swift b/swift/Package.swift
index 5d4c7cc..d2d2d5c 100644
--- a/swift/Package.swift
+++ b/swift/Package.swift
@@ -31,5 +31,6 @@
targets: [
.target(
name: "FlatBuffers",
- dependencies: []),
+ dependencies: [],
+ exclude: ["Documentation.docc/Resources/code/swift"]),
])
diff --git a/swift/Package@swift-5.5.swift b/swift/Package@swift-5.5.swift
new file mode 100644
index 0000000..3cfdcf6
--- /dev/null
+++ b/swift/Package@swift-5.5.swift
@@ -0,0 +1,36 @@
+// swift-tools-version:5.5
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import PackageDescription
+
+let package = Package(
+ name: "FlatBuffers",
+ platforms: [
+ .iOS(.v11),
+ .macOS(.v10_14),
+ ],
+ products: [
+ .library(
+ name: "FlatBuffers",
+ targets: ["FlatBuffers"]),
+ ],
+ targets: [
+ .target(
+ name: "FlatBuffers",
+ dependencies: []),
+ ])
+
diff --git a/swift/README.md b/swift/README.md
index c3060fd..6984fa8 100644
--- a/swift/README.md
+++ b/swift/README.md
@@ -10,8 +10,6 @@
1- To report any error please use the main repository.
-2- `0.6.0` deprecates `add(condition:bool)` for `add(element:bool)`. You can download the [binary here](https://github.com/google/flatbuffers/actions) and select the latest push to master
-
### Contribute
1- Always run `swift test --generate-linuxmain` whenever new test functions are added or removed
\ No newline at end of file
diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift
index 7df41a7..a07f66a 100644
--- a/swift/Sources/FlatBuffers/ByteBuffer.swift
+++ b/swift/Sources/FlatBuffers/ByteBuffer.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,10 @@
import Foundation
+/// `ByteBuffer` is the interface that stores the data for a `Flatbuffers` object
+/// it allows users to write and read data directly from memory thus the use of its
+/// functions should be used
+@frozen
public struct ByteBuffer {
/// Storage is a container that would hold the memory pointer to solve the issue of
@@ -29,12 +33,16 @@
/// Capacity of UInt8 the buffer can hold
var capacity: Int
+ @usableFromInline
init(count: Int, alignment: Int) {
- memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
+ memory = UnsafeMutableRawPointer.allocate(
+ byteCount: count,
+ alignment: alignment)
capacity = count
unowned = false
}
+ @usableFromInline
init(memory: UnsafeMutableRawPointer, capacity: Int, unowned: Bool) {
self.memory = memory
self.capacity = capacity
@@ -47,6 +55,7 @@
}
}
+ @usableFromInline
func copy(from ptr: UnsafeRawPointer, count: Int) {
assert(
!unowned,
@@ -54,6 +63,7 @@
memory.copyMemory(from: ptr, byteCount: count)
}
+ @usableFromInline
func initialize(for size: Int) {
assert(
!unowned,
@@ -64,7 +74,7 @@
/// Reallocates the buffer incase the object to be written doesnt fit in the current buffer
/// - Parameter size: Size of the current object
@usableFromInline
- internal func reallocate(_ size: Int, writerSize: Int, alignment: Int) {
+ func reallocate(_ size: Int, writerSize: Int, alignment: Int) {
let currentWritingIndex = capacity &- writerSize
while capacity <= writerSize &+ size {
capacity = capacity << 1
@@ -73,7 +83,9 @@
/// solution take from Apple-NIO
capacity = capacity.convertToPowerofTwo
- let newData = UnsafeMutableRawPointer.allocate(byteCount: capacity, alignment: alignment)
+ let newData = UnsafeMutableRawPointer.allocate(
+ byteCount: capacity,
+ alignment: alignment)
memset(newData, 0, capacity &- writerSize)
memcpy(
newData.advanced(by: capacity &- writerSize),
@@ -89,9 +101,9 @@
/// The size of the elements written to the buffer + their paddings
private var _writerSize: Int = 0
/// Aliginment of the current memory being written to the buffer
- internal var alignment = 1
+ var alignment = 1
/// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer
- internal var writerIndex: Int { _storage.capacity &- _writerSize }
+ var writerIndex: Int { _storage.capacity &- _writerSize }
/// Reader is the position of the current Writer Index (capacity - size)
public var reader: Int { writerIndex }
@@ -152,7 +164,10 @@
/// Constructor that creates a Flatbuffer from unsafe memory region without copying
/// - Parameter assumingMemoryBound: The unsafe memory region
/// - Parameter capacity: The size of the given memory region
- public init(assumingMemoryBound memory: UnsafeMutableRawPointer, capacity: Int) {
+ public init(
+ assumingMemoryBound memory: UnsafeMutableRawPointer,
+ capacity: Int)
+ {
_storage = Storage(memory: memory, capacity: capacity, unowned: true)
_writerSize = capacity
}
@@ -161,7 +176,7 @@
/// - Parameters:
/// - memory: Current memory of the buffer
/// - count: count of bytes
- internal init(memory: UnsafeMutableRawPointer, count: Int) {
+ init(memory: UnsafeMutableRawPointer, count: Int) {
_storage = Storage(count: count, alignment: alignment)
_storage.copy(from: memory, count: count)
_writerSize = _storage.capacity
@@ -172,7 +187,11 @@
/// - memory: Current memory of the buffer
/// - count: count of bytes
/// - removeBytes: Removes a number of bytes from the current size
- internal init(memory: UnsafeMutableRawPointer, count: Int, removing removeBytes: Int) {
+ init(
+ memory: UnsafeMutableRawPointer,
+ count: Int,
+ removing removeBytes: Int)
+ {
_storage = Storage(count: count, alignment: alignment)
_storage.copy(from: memory, count: count)
_writerSize = removeBytes
@@ -187,7 +206,7 @@
_writerSize = _writerSize &+ (MemoryLayout<UInt8>.size &* padding)
}
- ///Adds an array of type Scalar to the buffer memory
+ /// Adds an array of type Scalar to the buffer memory
/// - Parameter elements: An array of Scalars
@usableFromInline
mutating func push<T: Scalar>(elements: [T]) {
@@ -198,41 +217,16 @@
}
}
- /// A custom type of structs that are padded according to the flatbuffer padding,
+ /// Adds an object of type NativeStruct into the buffer
/// - Parameters:
- /// - value: Pointer to the object in memory
- /// - size: Size of Value being written to the buffer
- @available(
- *,
- deprecated,
- message: "0.9.0 will be removing the following method. Regenerate the code")
- @usableFromInline
- mutating func push(struct value: UnsafeMutableRawPointer, size: Int) {
+ /// - value: Object that will be written to the buffer
+ /// - size: size to subtract from the WriterIndex
+ @inline(__always)
+ mutating func push<T: NativeStruct>(struct value: T, size: Int) {
ensureSpace(size: size)
- memcpy(_storage.memory.advanced(by: writerIndex &- size), value, size)
- defer { value.deallocate() }
- _writerSize = _writerSize &+ size
- }
-
- /// Prepares the buffer to receive a struct of certian size.
- /// The alignment of the memory is already handled since we already called preAlign
- /// - Parameter size: size of the struct
- @usableFromInline
- mutating func prepareBufferToReceiveStruct(of size: Int) {
- ensureSpace(size: size)
- _writerSize = _writerSize &+ size
- }
-
- /// Reverse the input direction to the buffer, since `FlatBuffers` uses a back to front, following method will take current `writerIndex`
- /// and writes front to back into the buffer, respecting the padding & the alignment
- /// - Parameters:
- /// - value: value of type Scalar
- /// - position: position relative to the `writerIndex`
- /// - len: length of the value in terms of bytes
- @usableFromInline
- mutating func reversePush<T: Scalar>(value: T, position: Int, len: Int) {
var v = value
- memcpy(_storage.memory.advanced(by: writerIndex &+ position), &v, len)
+ memcpy(_storage.memory.advanced(by: writerIndex &- size), &v, size)
+ _writerSize = _writerSize &+ size
}
/// Adds an object of type Scalar into the buffer
@@ -253,7 +247,10 @@
@usableFromInline
mutating func push(string str: String, len: Int) {
ensureSpace(size: len)
- if str.utf8.withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != nil {
+ if str.utf8
+ .withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) !=
+ nil
+ {
} else {
let utf8View = str.utf8
for c in utf8View.reversed() {
@@ -266,8 +263,8 @@
/// - Parameters:
/// - bytes: Pointer to the view
/// - len: Size of string
- @usableFromInline
- mutating internal func push(
+ @inline(__always)
+ mutating func push(
bytes: UnsafeBufferPointer<String.UTF8View.Element>,
len: Int) -> Bool
{
@@ -300,7 +297,7 @@
/// Makes sure that buffer has enouch space for each of the objects that will be written into it
/// - Parameter size: size of object
@discardableResult
- @usableFromInline
+ @inline(__always)
mutating func ensureSpace(size: Int) -> Int {
if size &+ _writerSize > _storage.capacity {
_storage.reallocate(size, writerSize: _writerSize, alignment: alignment)
@@ -311,9 +308,11 @@
/// pops the written VTable if it's already written into the buffer
/// - Parameter size: size of the `VTable`
- @usableFromInline
- mutating internal func pop(_ size: Int) {
- assert((_writerSize &- size) > 0, "New size should NOT be a negative number")
+ @inline(__always)
+ mutating func pop(_ size: Int) {
+ assert(
+ (_writerSize &- size) > 0,
+ "New size should NOT be a negative number")
memset(_storage.memory.advanced(by: writerIndex), 0, _writerSize &- size)
_writerSize = size
}
@@ -335,25 +334,24 @@
/// - def: Type of the object
/// - position: the index of the object in the buffer
public func read<T>(def: T.Type, position: Int) -> T {
- assert(
- position + MemoryLayout<T>.size <= _storage.capacity,
- "Reading out of bounds is illegal")
- return _storage.memory.advanced(by: position).load(as: T.self)
+ _storage.memory.advanced(by: position).load(as: T.self)
}
/// Reads a slice from the memory assuming a type of T
/// - Parameters:
/// - index: index of the object to be read from the buffer
/// - count: count of bytes in memory
+ @inline(__always)
public func readSlice<T>(
- index: Int32,
- count: Int32) -> [T]
+ index: Int,
+ count: Int) -> [T]
{
- let _index = Int(index)
- let _count = Int(count)
- assert(_index + _count <= _storage.capacity, "Reading out of bounds is illegal")
- let start = _storage.memory.advanced(by: _index).assumingMemoryBound(to: T.self)
- let array = UnsafeBufferPointer(start: start, count: _count)
+ assert(
+ index + count <= _storage.capacity,
+ "Reading out of bounds is illegal")
+ let start = _storage.memory.advanced(by: index)
+ .assumingMemoryBound(to: T.self)
+ let array = UnsafeBufferPointer(start: start, count: count)
return Array(array)
}
@@ -363,15 +361,16 @@
/// - count: length of the string
/// - type: Encoding of the string
public func readString(
- at index: Int32,
- count: Int32,
+ at index: Int,
+ count: Int,
type: String.Encoding = .utf8) -> String?
{
- let _index = Int(index)
- let _count = Int(count)
- assert(_index + _count <= _storage.capacity, "Reading out of bounds is illegal")
- let start = _storage.memory.advanced(by: _index).assumingMemoryBound(to: UInt8.self)
- let bufprt = UnsafeBufferPointer(start: start, count: _count)
+ assert(
+ index + count <= _storage.capacity,
+ "Reading out of bounds is illegal")
+ let start = _storage.memory.advanced(by: index)
+ .assumingMemoryBound(to: UInt8.self)
+ let bufprt = UnsafeBufferPointer(start: start, count: count)
return String(bytes: Array(bufprt), encoding: type)
}
@@ -379,12 +378,32 @@
/// - Parameter removeBytes: the amount of bytes to remove from the current Size
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
assert(removeBytes > 0, "Can NOT remove negative bytes")
- assert(removeBytes < _storage.capacity, "Can NOT remove more bytes than the ones allocated")
+ assert(
+ removeBytes < _storage.capacity,
+ "Can NOT remove more bytes than the ones allocated")
return ByteBuffer(
memory: _storage.memory,
count: _storage.capacity,
removing: _writerSize &- removeBytes)
}
+
+ /// Returns the written bytes into the ``ByteBuffer``
+ public var underlyingBytes: [UInt8] {
+ let cp = capacity &- writerIndex
+ let start = memory.advanced(by: writerIndex)
+ .bindMemory(to: UInt8.self, capacity: cp)
+
+ let ptr = UnsafeBufferPointer<UInt8>(start: start, count: cp)
+ return Array(ptr)
+ }
+
+ /// SkipPrefix Skips the first 4 bytes in case one of the following
+ /// functions are called `getPrefixedSizeCheckedRoot` & `getPrefixedSizeRoot`
+ /// which allows us to skip the first 4 bytes instead of recreating the buffer
+ @usableFromInline
+ mutating func skipPrefix() {
+ _writerSize = _writerSize &- MemoryLayout<Int32>.size
+ }
}
extension ByteBuffer: CustomDebugStringConvertible {
diff --git a/swift/Sources/FlatBuffers/Constants.swift b/swift/Sources/FlatBuffers/Constants.swift
index ac541d9..8e643fd 100644
--- a/swift/Sources/FlatBuffers/Constants.swift
+++ b/swift/Sources/FlatBuffers/Constants.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
#endif
/// A boolean to see if the system is littleEndian
-let isLitteEndian = CFByteOrderGetCurrent() == Int(CFByteOrderLittleEndian.rawValue)
+let isLitteEndian = CFByteOrderGetCurrent() ==
+ Int(CFByteOrderLittleEndian.rawValue)
/// Constant for the file id length
let FileIdLength = 4
/// Type aliases
@@ -30,16 +31,19 @@
public typealias SOffset = Int32
public typealias VOffset = UInt16
/// Maximum size for a buffer
-public let FlatBufferMaxSize = UInt32.max << ((MemoryLayout<SOffset>.size * 8 - 1) - 1)
+public let FlatBufferMaxSize = UInt32
+ .max << ((MemoryLayout<SOffset>.size * 8 - 1) - 1)
-/// Protocol that confirms all the numbers
+/// Protocol that All Scalars should conform to
///
-/// Scalar is used to confirm all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
+/// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
public protocol Scalar: Equatable {
associatedtype NumericValue
var convertedEndian: NumericValue { get }
}
+extension Scalar where Self: Verifiable {}
+
extension Scalar where Self: FixedWidthInteger {
/// Converts the value from BigEndian to LittleEndian
///
@@ -49,7 +53,7 @@
}
}
-extension Double: Scalar {
+extension Double: Scalar, Verifiable {
public typealias NumericValue = UInt64
public var convertedEndian: UInt64 {
@@ -57,7 +61,7 @@
}
}
-extension Float32: Scalar {
+extension Float32: Scalar, Verifiable {
public typealias NumericValue = UInt32
public var convertedEndian: UInt32 {
@@ -65,7 +69,7 @@
}
}
-extension Bool: Scalar {
+extension Bool: Scalar, Verifiable {
public var convertedEndian: UInt8 {
self == true ? 1 : 0
}
@@ -73,40 +77,40 @@
public typealias NumericValue = UInt8
}
-extension Int: Scalar {
+extension Int: Scalar, Verifiable {
public typealias NumericValue = Int
}
-extension Int8: Scalar {
+extension Int8: Scalar, Verifiable {
public typealias NumericValue = Int8
}
-extension Int16: Scalar {
+extension Int16: Scalar, Verifiable {
public typealias NumericValue = Int16
}
-extension Int32: Scalar {
+extension Int32: Scalar, Verifiable {
public typealias NumericValue = Int32
}
-extension Int64: Scalar {
+extension Int64: Scalar, Verifiable {
public typealias NumericValue = Int64
}
-extension UInt8: Scalar {
+extension UInt8: Scalar, Verifiable {
public typealias NumericValue = UInt8
}
-extension UInt16: Scalar {
+extension UInt16: Scalar, Verifiable {
public typealias NumericValue = UInt16
}
-extension UInt32: Scalar {
+extension UInt32: Scalar, Verifiable {
public typealias NumericValue = UInt32
}
-extension UInt64: Scalar {
+extension UInt64: Scalar, Verifiable {
public typealias NumericValue = UInt64
}
-public func FlatBuffersVersion_1_12_0() {}
+public func FlatBuffersVersion_2_0_0() {}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Documentation.md b/swift/Sources/FlatBuffers/Documentation.docc/Documentation.md
new file mode 100644
index 0000000..a151080
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Documentation.md
@@ -0,0 +1,22 @@
+# ``FlatBuffers``
+
+FlatBuffers: Memory Efficient Serialization Library
+
+## Overview
+
+- Access to serialized data without parsing/unpacking - What sets FlatBuffers apart is that it represents hierarchical data in a flat binary buffer in such a way that it can still be accessed directly without parsing/unpacking, while also still supporting data structure evolution (forwards/backwards compatibility).
+- Memory efficiency and speed - The only memory needed to access your data is that of the buffer. It requires 0 additional allocations (in C++, other languages may vary). FlatBuffers is also very suitable for use with mmap (or streaming), requiring only part of the buffer to be in memory. Access is close to the speed of raw struct access with only one extra indirection (a kind of vtable) to allow for format evolution and optional fields. It is aimed at projects where spending time and space (many memory allocations) to be able to access or construct serialized data is undesirable, such as in games or any other performance sensitive applications. See the benchmarks for details.
+- Flexible - Optional fields means not only do you get great forwards and backwards compatibility (increasingly important for long-lived games: don't have to update all data with each new version!). It also means you have a lot of choice in what data you write and what data you don't, and how you design data structures.
+- Tiny code footprint - Small amounts of generated code, and just a single small header as the minimum dependency, which is very easy to integrate. Again, see the benchmark section for details.
+- Strongly typed - Errors happen at compile time rather than manually having to write repetitive and error prone run-time checks. Useful code can be generated for you.
+
+## Topics
+
+### Read this first
+
+- <doc:Tutorial_Table_of_Contents>
+
+### Where to start
+
+- ``FlatBufferBuilder``
+- ``ByteBuffer``
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_1.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_1.fbs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_1.fbs
@@ -0,0 +1 @@
+
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_2.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_2.fbs
new file mode 100644
index 0000000..a438978
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_2.fbs
@@ -0,0 +1 @@
+enum Color:byte { red, green, blue }
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_3.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_3.fbs
new file mode 100644
index 0000000..d31a29c
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_3.fbs
@@ -0,0 +1,6 @@
+enum Color:byte { red, green, blue }
+
+struct Vec3 {
+ x:float;
+ y:float;
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_4.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_4.fbs
new file mode 100644
index 0000000..51f7bb1
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_4.fbs
@@ -0,0 +1,12 @@
+enum Color:byte { red, green, blue }
+
+struct Vec3 {
+ x:float;
+ y:float;
+}
+
+table Monster {
+ pos:Vec3;
+ color:Color = Blue;
+}
+
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_5.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_5.fbs
new file mode 100644
index 0000000..8d0b729
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_5.fbs
@@ -0,0 +1,18 @@
+enum Color:byte { red, green, blue }
+
+struct Vec3 {
+ x:float;
+ y:float;
+}
+
+table Monster {
+ pos:Vec3;
+ color:Color = Blue;
+
+ mana:short = 150;
+ hp:short = 100;
+ name:string;
+ equipped:Equipment;
+ weapons:[Weapon];
+ path:[Vec3];
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_6.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_6.fbs
new file mode 100644
index 0000000..10c3eaf
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_6.fbs
@@ -0,0 +1,25 @@
+enum Color:byte { red, green, blue }
+
+union Equipment { Weapon } // Optionally add more tables.
+
+struct Vec3 {
+ x:float;
+ y:float;
+}
+
+table Monster {
+ pos:Vec3;
+ color:Color = Blue;
+
+ mana:short = 150;
+ hp:short = 100;
+ name:string;
+ equipped:Equipment;
+ weapons:[Weapon];
+ path:[Vec3];
+}
+
+table Weapon {
+ name:string;
+ damage:short;
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_7.fbs b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_7.fbs
new file mode 100644
index 0000000..b4dde6c
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/fbs/monster_step_7.fbs
@@ -0,0 +1,27 @@
+enum Color:byte { red, green, blue }
+
+union Equipment { Weapon } // Optionally add more tables.
+
+struct Vec3 {
+ x:float;
+ y:float;
+}
+
+table Monster {
+ pos:Vec3;
+ color:Color = Blue;
+
+ mana:short = 150;
+ hp:short = 100;
+ name:string;
+ equipped:Equipment;
+ weapons:[Weapon];
+ path:[Vec3];
+}
+
+table Weapon {
+ name:string;
+ damage:short;
+}
+
+root_type Monster; // flatc --swift monster.fbs
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_1.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_1.swift
new file mode 100644
index 0000000..fecc4ab
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_1.swift
@@ -0,0 +1 @@
+import Foundation
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_10.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_10.swift
new file mode 100644
index 0000000..51d4fbf
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_10.swift
@@ -0,0 +1,71 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon1Name, &builder)
+ Weapon.add(damage: 3, &builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(&builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon2Name, &builder)
+ Weapon.add(damage: 5, &builder)
+ let axe = Weapon.endWeapon(&builder, start: weapon2Start)
+
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+
+ // Name of the Monster.
+ let name = builder.create(string: "Orc")
+
+ let pathOffset = fbb.createVector(ofStructs: [
+ Vec3(x: 0, y: 0),
+ Vec3(x: 5, y: 5),
+ ])
+
+ // startVector(len, elementSize: MemoryLayout<Offset>.size)
+ // for o in offsets.reversed() {
+ // push(element: o)
+ // }
+ // endVector(len: len)
+
+ let orc = Monster.createMonster(
+ &builder,
+ pos: Vec3(x: 1, y: 2),
+ hp: 300,
+ nameOffset: name,
+ color: .red,
+ weaponsVectorOffset: weaponsOffset,
+ equippedType: .weapon,
+ equippedOffset: axe,
+ pathOffset: pathOffset)
+
+ // let start = Monster.startMonster(&builder)
+ // Monster.add(pos: Vec3(x: 1, y: 2), &builder)
+ // Monster.add(hp: 300, &builder)
+ // Monster.add(name: name, &builder)
+ // Monster.add(color: .red, &builder)
+ // Monster.addVectorOf(weapons: weaponsOffset, &builder)
+ // Monster.add(equippedType: .weapon, &builder)
+ // Monster.addVectorOf(paths: weaponsOffset, &builder)
+ // Monster.add(equipped: axe, &builder)
+ // var orc = Monster.endMonster(&builder, start: start)
+
+ // Call `finish(offset:)` to instruct the builder that this monster is complete.
+ builder.finish(offset: orc)
+ // This must be called after `finish()`.
+ // `sizedByteArray` returns the finished buf of type [UInt8].
+ let buf = builder.sizedByteArray
+
+ // or you can use to get an object of type Data
+ let bufData = ByteBuffer(data: builder.sizedBuffer)
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_11.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_11.swift
new file mode 100644
index 0000000..3ed7ea2
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_11.swift
@@ -0,0 +1,11 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a ByteBuffer(:) from an [UInt8] or Data()
+ let buf = [] // Get your data
+
+ // Get an accessor to the root object inside the buffer.
+ let monster: Monster = try! getCheckedRoot(byteBuffer: ByteBuffer(bytes: buf))
+ // let monster: Monster = getRoot(byteBuffer: ByteBuffer(bytes: buf))
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_12.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_12.swift
new file mode 100644
index 0000000..895653e
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_12.swift
@@ -0,0 +1,19 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a ByteBuffer(:) from an [UInt8] or Data()
+ let buf = [] // Get your data
+
+ // Get an accessor to the root object inside the buffer.
+ let monster: Monster = try! getCheckedRoot(byteBuffer: ByteBuffer(bytes: buf))
+ // let monster: Monster = getRoot(byteBuffer: ByteBuffer(bytes: buf))
+
+ let hp = monster.hp
+ let mana = monster.mana
+ let name = monster.name // returns an optional string
+
+ let pos = monster.pos
+ let x = pos.x
+ let y = pos.y
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_13.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_13.swift
new file mode 100644
index 0000000..7aac982
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_13.swift
@@ -0,0 +1,26 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a ByteBuffer(:) from an [UInt8] or Data()
+ let buf = [] // Get your data
+
+ // Get an accessor to the root object inside the buffer.
+ let monster: Monster = try! getCheckedRoot(byteBuffer: ByteBuffer(bytes: buf))
+ // let monster: Monster = getRoot(byteBuffer: ByteBuffer(bytes: buf))
+
+ let hp = monster.hp
+ let mana = monster.mana
+ let name = monster.name // returns an optional string
+
+ let pos = monster.pos
+ let x = pos.x
+ let y = pos.y
+
+ // Get and check if the monster has an equipped item
+ if monster.equippedType == .weapon {
+ let _weapon = monster.equipped(type: Weapon.self)
+ let name = _weapon.name // should return "Axe"
+ let dmg = _weapon.damage // should return 5
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_2.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_2.swift
new file mode 100644
index 0000000..ddd066e
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_2.swift
@@ -0,0 +1,2 @@
+import FlatBuffers
+import Foundation
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_3.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_3.swift
new file mode 100644
index 0000000..bacdaa5
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_3.swift
@@ -0,0 +1,7 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_4.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_4.swift
new file mode 100644
index 0000000..8754699
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_4.swift
@@ -0,0 +1,10 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_5.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_5.swift
new file mode 100644
index 0000000..12e0d4c
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_5.swift
@@ -0,0 +1,22 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon1Name, &builder)
+ Weapon.add(damage: 3, &builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(&builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon2Name, &builder)
+ Weapon.add(damage: 5, &builder)
+ let axe = Weapon.endWeapon(&builder, start: weapon2Start)
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_6.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_6.swift
new file mode 100644
index 0000000..bfb4f7e
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_6.swift
@@ -0,0 +1,26 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon1Name, &builder)
+ Weapon.add(damage: 3, &builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(&builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon2Name, &builder)
+ Weapon.add(damage: 5, &builder)
+ let axe = Weapon.endWeapon(&builder, start: weapon2Start)
+
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_7.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_7.swift
new file mode 100644
index 0000000..97264b0
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_7.swift
@@ -0,0 +1,29 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon1Name, &builder)
+ Weapon.add(damage: 3, &builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(&builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon2Name, &builder)
+ Weapon.add(damage: 5, &builder)
+ let axe = Weapon.endWeapon(&builder, start: weapon2Start)
+
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+
+ // Name of the Monster.
+ let name = builder.create(string: "Orc")
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_8.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_8.swift
new file mode 100644
index 0000000..a0c2819
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_8.swift
@@ -0,0 +1,40 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon1Name, &builder)
+ Weapon.add(damage: 3, &builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(&builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon2Name, &builder)
+ Weapon.add(damage: 5, &builder)
+ let axe = Weapon.endWeapon(&builder, start: weapon2Start)
+
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+
+ // Name of the Monster.
+ let name = builder.create(string: "Orc")
+
+ let pathOffset = fbb.createVector(ofStructs: [
+ Vec3(x: 0, y: 0),
+ Vec3(x: 5, y: 5),
+ ])
+
+ // startVector(len, elementSize: MemoryLayout<Offset>.size)
+ // for o in offsets.reversed() {
+ // push(element: o)
+ // }
+ // endVector(len: len)
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_9.swift b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_9.swift
new file mode 100644
index 0000000..51ce8fd
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/code/swift/swift_code_9.swift
@@ -0,0 +1,62 @@
+import FlatBuffers
+import Foundation
+
+func run() {
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon1Name, &builder)
+ Weapon.add(damage: 3, &builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(&builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(&builder)
+ Weapon.add(name: weapon2Name, &builder)
+ Weapon.add(damage: 5, &builder)
+ let axe = Weapon.endWeapon(&builder, start: weapon2Start)
+
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+
+ // Name of the Monster.
+ let name = builder.create(string: "Orc")
+
+ let pathOffset = fbb.createVector(ofStructs: [
+ Vec3(x: 0, y: 0),
+ Vec3(x: 5, y: 5),
+ ])
+
+ // startVector(len, elementSize: MemoryLayout<Offset>.size)
+ // for o in offsets.reversed() {
+ // push(element: o)
+ // }
+ // endVector(len: len)
+
+ let orc = Monster.createMonster(
+ &builder,
+ pos: Vec3(x: 1, y: 2),
+ hp: 300,
+ nameOffset: name,
+ color: .red,
+ weaponsVectorOffset: weaponsOffset,
+ equippedType: .weapon,
+ equippedOffset: axe,
+ pathOffset: pathOffset)
+
+ // let start = Monster.startMonster(&builder)
+ // Monster.add(pos: Vec3(x: 1, y: 2), &builder)
+ // Monster.add(hp: 300, &builder)
+ // Monster.add(name: name, &builder)
+ // Monster.add(color: .red, &builder)
+ // Monster.addVectorOf(weapons: weaponsOffset, &builder)
+ // Monster.add(equippedType: .weapon, &builder)
+ // Monster.addVectorOf(paths: weaponsOffset, &builder)
+ // Monster.add(equipped: axe, &builder)
+ // var orc = Monster.endMonster(&builder, start: start)
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Resources/images/tutorial_cover_image_1.png b/swift/Sources/FlatBuffers/Documentation.docc/Resources/images/tutorial_cover_image_1.png
new file mode 100644
index 0000000..0e64fe6
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Resources/images/tutorial_cover_image_1.png
Binary files differ
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/Tutorial_Table_of_Contents.tutorial b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/Tutorial_Table_of_Contents.tutorial
new file mode 100644
index 0000000..009116f
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/Tutorial_Table_of_Contents.tutorial
@@ -0,0 +1,14 @@
+@Tutorials(name: "Starting with FlatBuffers") {
+ @Intro(title: "Starting with FlatBuffers") {
+ FlatBuffers is an efficient cross platform serialization library for C++,
+ C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, Rust and Swift.
+ It was originally created at Google for game development and other performance-critical applications.
+ }
+ @Chapter(name: "Generating your code") {
+ Start by generating your first FlatBuffers objects.
+ @Image(source: tutorial_cover_image_1.png, alt: "A code structure for a base struct in flatbuffers")
+ @TutorialReference(tutorial: "doc:creating_flatbuffer_schema")
+ @TutorialReference(tutorial: "doc:create_your_first_buffer")
+ @TutorialReference(tutorial: "doc:reading_bytebuffer")
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/create_your_first_buffer.tutorial b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/create_your_first_buffer.tutorial
new file mode 100644
index 0000000..2f8089f
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/create_your_first_buffer.tutorial
@@ -0,0 +1,72 @@
+@Tutorial(time: 5) {
+ @Intro(title: "After having our code generated") {
+ After generating the code from the previous section, we will know start creating our monster object.
+ We will create a monster object called orc.
+ }
+
+ @Section(title: "Building your first buffer") {
+ @ContentAndMedia {}
+ @Steps {
+ @Step {
+ Starting with a new file, we will create our very first Flatbuffer.
+ @Code(name: "ViewController.swift", file: "swift_code_1.swift")
+ }
+ @Step {
+ First, we need to import ``FlatBuffers``
+ @Code(name: "ViewController.swift", file: "swift_code_2.swift")
+ }
+ @Step {
+ We need to create an instance of the `FlatBufferBuilder`, which will contain the buffer as it grows.
+ You can pass an initial size of the buffer (here 1024 bytes), which will grow automatically if needed.
+ @Code(name: "ViewController.swift", file: "swift_code_3.swift")
+ }
+ @Step {
+ After creating the builder, we can start serializing our data. Before we make our orc Monster,
+ let's create some Weapons: a Sword and an Axe. However we will start by naming our weapons as `Sword` and `Axe`
+ @Code(name: "ViewController.swift", file: "swift_code_4.swift")
+ }
+ @Step {
+ After naming the weapons, we will create two weapon objects with the damage that the weapon is going to deal.
+ That's done by calling the `start` Method on each table you will be creating, in this case its called `startWeapon`
+ and finished by calling `end`.
+ @Code(name: "ViewController.swift", file: "swift_code_5.swift")
+ }
+ @Step {
+ We will take our (Sword and Axe) serialized data and serialize their offsets as a vector of tables into our `ByteBuffer`.
+ So we can reference them later on from our Monster Object
+ @Code(name: "ViewController.swift", file: "swift_code_6.swift")
+ }
+ @Step {
+ We will add our Monster name as a string value just like we did with the weapons.
+ @Code(name: "ViewController.swift", file: "swift_code_7.swift")
+ }
+
+ @Step {
+ We will create a path that our monster should be using while roaming in its den. To create a vector of paths we would us
+ `createVector(ofStructs: [])` which will take a Native `Swift` struct that has been padded to fit the `FlatBuffers` standards.
+
+ There are usually two ways of creating vectors in `FlatBuffers` which you can see in commented out code.
+ And thus there are multiple convenience methods that will cover all the bases
+ when trying to create a vector so that you dont have to create it with `start` and `end`
+ @Code(name: "ViewController.swift", file: "swift_code_8.swift")
+ }
+
+ @Step {
+ Now to serialize our data into our `Monster` object. Which again there are two ways of doing, by calling the `create` method or
+ by serializing the objects yourself. What we added to our Monster were the `Equipped Type` and the `Equipped` union itself, which
+ allows the Monster to have the `Axe` as his equipped weapon.
+
+ Important: Unlike structs, you should not nest tables or other objects,
+ which is why we created all the `strings/vectors/tables` that this monster refers to before start.
+ If you try to create any of them between start and end, you will get an `assert`.
+ @Code(name: "ViewController.swift", file: "swift_code_9.swift")
+ }
+
+ @Step {
+ Finally you can just finalize the buffer by calling `builder.finish` and get the Byte array from the buffer.
+ @Code(name: "ViewController.swift", file: "swift_code_10.swift")
+ }
+
+ }
+ }
+ }
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/creating_flatbuffer_schema.tutorial b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/creating_flatbuffer_schema.tutorial
new file mode 100644
index 0000000..0fcd362
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/creating_flatbuffer_schema.tutorial
@@ -0,0 +1,47 @@
+@Tutorial(time: 2) {
+ @Intro(title: "Creating a schema") {
+ You will need to have the FlatBuffer compiler to be installed on your device
+ }
+
+ @Section(title: "Creating a schema") {
+ @ContentAndMedia {}
+ @Steps {
+ @Step {
+ Start by creating a new empty folder called `monster.fbs`. We want to create a Monster table, that contains
+ position, color, and basic information about the monster.
+ @Code(name: "monster.fbs", file: "monster_step_1.fbs")
+ }
+ @Step {
+ We will start by adding our Color object. We will be using an enumerate, to represent this object
+ @Code(name: "monster.fbs", file: "monster_step_2.fbs")
+ }
+ @Step {
+ We will add a position object and will use a struct to represent that type of data. Where we will need the monsters
+ x and y positions.
+ @Code(name: "monster.fbs", file: "monster_step_3.fbs")
+ }
+ @Step {
+ Then we will be creating our Monster object of type table. This will contain the current position of our
+ monster and its color
+ @Code(name: "monster.fbs", file: "monster_step_4.fbs")
+ }
+ @Step {
+ Our Monster is missing a name, mana, hp, name, equipped Weapon, weapons, and path. We will be adding these
+ fields to our table with a proper data type for each. Example; weapons, and path would be a vector of data.
+ @Code(name: "monster.fbs", file: "monster_step_5.fbs")
+ }
+ @Step {
+ Now we are missing two data types here, `Weapon` and `Equipment`. And since Equipment can be a weapon, we will be using
+ a `Union` enumerate that can contain all the equipment that you would want your monster to have. And the weapon can simply
+ have a name and amount of damage
+ @Code(name: "monster.fbs", file: "monster_step_6.fbs")
+ }
+ @Step {
+ And to finalize our monster table, we can add a root type of type Monster.
+ Then run the command `flatc --swift monster.fbs`
+ Note: Make sure to import the file to your xcode project.
+ @Code(name: "monster.fbs", file: "monster_step_7.fbs")
+ }
+ }
+ }
+ }
diff --git a/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/reading_bytebuffer.tutorial b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/reading_bytebuffer.tutorial
new file mode 100644
index 0000000..2c4609f
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Documentation.docc/Tutorials/reading_bytebuffer.tutorial
@@ -0,0 +1,27 @@
+@Tutorial(time: 2) {
+ @Intro(title: "Reading ByteBuffers") {
+ After getting our ByteBuffer created, we can now read it.
+ }
+
+ @Section(title: "Reading your first buffer") {
+ @ContentAndMedia {}
+ @Steps {
+ @Step {
+ After fetching the data from disk or network you need to access that data, and that can be done.
+ By simply calling `getCheckedRoot`, which checks if the data is valid before enabling you to read from a corrupt buffer.
+ however, if you are sure that the data is 100% correct you can simply call `getRoot`
+ @Code(name: "ViewController.swift", file: "swift_code_11.swift")
+ }
+ @Step {
+ Now since we have a Monster object, all the fields can be accessed by simply fetching the data. Note, Deprecated fields will not
+ show up
+ @Code(name: "ViewController.swift", file: "swift_code_12.swift")
+ }
+ @Step {
+ And you can access union types as easy as this
+ @Code(name: "ViewController.swift", file: "swift_code_13.swift")
+ }
+ }
+ }
+ }
+
diff --git a/swift/Sources/FlatBuffers/Enum.swift b/swift/Sources/FlatBuffers/Enum.swift
new file mode 100644
index 0000000..efb698b
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Enum.swift
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// Enum is a protocol that all flatbuffers enums should conform to
+/// Since it allows us to get the actual `ByteSize` and `Value` from
+/// a swift enum.
+public protocol Enum {
+ /// associatedtype that the type of the enum should conform to
+ associatedtype T: Scalar & Verifiable
+ /// Size of the current associatedtype in the enum
+ static var byteSize: Int { get }
+ /// The current value the enum hosts
+ var value: T { get }
+}
+
+extension Enum where Self: Verifiable {
+
+ /// Verifies that the current value is which the bounds of the buffer, and if
+ /// the current `Value` is aligned properly
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Errors coming from `inBuffer` function
+ public static func verify<T>(
+ _ verifier: inout Verifier,
+ at position: Int,
+ of type: T.Type) throws where T: Verifiable
+ {
+ try verifier.inBuffer(position: position, of: type.self)
+ }
+
+}
+
+/// UnionEnum is a Protocol that allows us to create Union type of enums
+/// and their value initializers. Since an `init` was required by
+/// the verifier
+public protocol UnionEnum: Enum {
+ init?(value: T) throws
+}
diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift
index 71fcab0..5ccc7e4 100644
--- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift
+++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,19 +16,30 @@
import Foundation
+/// ``FlatBufferBuilder`` builds a `FlatBuffer` through manipulating its internal state.
+///
+/// This is done by creating a ``ByteBuffer`` that hosts the incoming data and
+/// has a hardcoded growth limit of `2GiB` which is set by the Flatbuffers standards.
+///
+/// ```swift
+/// var builder = FlatBufferBuilder()
+/// ```
+/// The builder should be always created as a variable, since it would be passed into the writers
+///
+@frozen
public struct FlatBufferBuilder {
/// Storage for the Vtables used in the buffer are stored in here, so they would be written later in EndTable
@usableFromInline internal var _vtableStorage = VTableStorage()
+ /// Flatbuffer data will be written into
+ @usableFromInline internal var _bb: ByteBuffer
/// Reference Vtables that were already written to the buffer
private var _vtables: [UOffset] = []
- /// Flatbuffer data will be written into
- private var _bb: ByteBuffer
/// A check if the buffer is being written into by a different table
private var isNested = false
/// Dictonary that stores a map of all the strings that were written to the buffer
- private var stringOffsetMap: [String: Offset<String>] = [:]
+ private var stringOffsetMap: [String: Offset] = [:]
/// A check to see if finish(::) was ever called to retreive data object
private var finished = false
/// A check to see if the buffer should serialize Default values
@@ -43,55 +54,76 @@
/// Gives a read access to the buffer's size
public var size: UOffset { _bb.size }
+
/// Data representation of the buffer
+ ///
+ /// Should only be used after ``finish(offset:addPrefix:)`` is called
public var data: Data {
assert(finished, "Data shouldn't be called before finish()")
return Data(
bytes: _bb.memory.advanced(by: _bb.writerIndex),
count: _bb.capacity &- _bb.writerIndex)
}
- /// Get's the fully sized buffer stored in memory
+
+ /// Returns the underlying bytes in the ``ByteBuffer``
+ ///
+ /// Note: This should be used with caution.
public var fullSizedByteArray: [UInt8] {
let ptr = UnsafeBufferPointer(
start: _bb.memory.assumingMemoryBound(to: UInt8.self),
count: _bb.capacity)
return Array(ptr)
}
- /// Returns the written size of the buffer
+
+ /// Returns the written bytes into the ``ByteBuffer``
+ ///
+ /// Should only be used after ``finish(offset:addPrefix:)`` is called
public var sizedByteArray: [UInt8] {
assert(finished, "Data shouldn't be called before finish()")
- let cp = _bb.capacity &- _bb.writerIndex
- let start = _bb.memory.advanced(by: _bb.writerIndex)
- .bindMemory(to: UInt8.self, capacity: cp)
-
- let ptr = UnsafeBufferPointer(start: start, count: cp)
- return Array(ptr)
+ return _bb.underlyingBytes
}
- /// Returns the buffer
+
+ /// Returns the original ``ByteBuffer``
+ ///
+ /// Returns the current buffer that was just created
+ /// with the offsets, and data written to it.
public var buffer: ByteBuffer { _bb }
- /// Returns A sized Buffer from the readable bytes
+ /// Returns a newly created sized ``ByteBuffer``
+ ///
+ /// returns a new buffer that is sized to the data written
+ /// to the main buffer
public var sizedBuffer: ByteBuffer {
assert(finished, "Data shouldn't be called before finish()")
- return ByteBuffer(memory: _bb.memory.advanced(by: _bb.reader), count: Int(_bb.size))
+ return ByteBuffer(
+ memory: _bb.memory.advanced(by: _bb.reader),
+ count: Int(_bb.size))
}
// MARK: - Init
- /// initialize the buffer with a size
+ /// Initialize the buffer with a size
/// - Parameters:
/// - initialSize: Initial size for the buffer
/// - force: Allows default to be serialized into the buffer
- public init(initialSize: Int32 = 1024, serializeDefaults force: Bool = false) {
+ ///
+ /// This initializes a new builder with an initialSize that would initialize
+ /// a new ``ByteBuffer``. ``FlatBufferBuilder`` by default doesnt serialize defaults
+ /// however the builder can be force by passing true for `serializeDefaults`
+ public init(
+ initialSize: Int32 = 1024,
+ serializeDefaults force: Bool = false)
+ {
assert(initialSize > 0, "Size should be greater than zero!")
guard isLitteEndian else {
- fatalError("Reading/Writing a buffer in big endian machine is not supported on swift")
+ fatalError(
+ "Reading/Writing a buffer in big endian machine is not supported on swift")
}
serializeDefaults = force
_bb = ByteBuffer(initialSize: Int(initialSize))
}
- /// Clears the buffer and the builder from it's data
+ /// Clears the builder and the buffer from the written data.
mutating public func clear() {
_minAlignment = 0
isNested = false
@@ -107,11 +139,16 @@
/// - Parameters:
/// - table: offset for the table
/// - fields: Array of all the important fields to be serialized
- mutating public func require(table: Offset<UOffset>, fields: [Int32]) {
+ ///
+ /// *NOTE: Never call this function, this is only supposed to be called
+ /// by the generated code*
+ mutating public func require(table: Offset, fields: [Int32]) {
for field in fields {
let start = _bb.capacity &- Int(table.o)
let startTable = start &- Int(_bb.read(def: Int32.self, position: start))
- let isOkay = _bb.read(def: VOffset.self, position: startTable &+ Int(field)) != 0
+ let isOkay = _bb.read(
+ def: VOffset.self,
+ position: startTable &+ Int(field)) != 0
assert(isOkay, "Flatbuffers requires the following field")
}
}
@@ -121,9 +158,32 @@
/// - offset: Offset of the table
/// - fileId: Takes the fileId
/// - prefix: if false it wont add the size of the buffer
- mutating public func finish<T>(offset: Offset<T>, fileId: String, addPrefix prefix: Bool = false) {
+ ///
+ /// ``finish(offset:fileId:addPrefix:)`` should be called at the end of creating
+ /// a table
+ /// ```swift
+ /// var root = SomeObject
+ /// .createObject(&builder,
+ /// name: nameOffset)
+ /// builder.finish(
+ /// offset: root,
+ /// fileId: "ax1a",
+ /// addPrefix: true)
+ /// ```
+ /// File id would append a file id name at the end of the written bytes before,
+ /// finishing the buffer.
+ ///
+ /// Whereas, if `addPrefix` is true, the written bytes would
+ /// include the size of the current buffer.
+ mutating public func finish(
+ offset: Offset,
+ fileId: String,
+ addPrefix prefix: Bool = false)
+ {
let size = MemoryLayout<UOffset>.size
- preAlign(len: size &+ (prefix ? size : 0) &+ FileIdLength, alignment: _minAlignment)
+ preAlign(
+ len: size &+ (prefix ? size : 0) &+ FileIdLength,
+ alignment: _minAlignment)
assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4")
_bb.push(string: fileId, len: 4)
finish(offset: offset, addPrefix: prefix)
@@ -133,7 +193,23 @@
/// - Parameters:
/// - offset: Offset of the table
/// - prefix: if false it wont add the size of the buffer
- mutating public func finish<T>(offset: Offset<T>, addPrefix prefix: Bool = false) {
+ ///
+ /// ``finish(offset:addPrefix:)`` should be called at the end of creating
+ /// a table
+ /// ```swift
+ /// var root = SomeObject
+ /// .createObject(&builder,
+ /// name: nameOffset)
+ /// builder.finish(
+ /// offset: root,
+ /// addPrefix: true)
+ /// ```
+ /// If `addPrefix` is true, the written bytes would
+ /// include the size of the current buffer.
+ mutating public func finish(
+ offset: Offset,
+ addPrefix prefix: Bool = false)
+ {
notNested()
let size = MemoryLayout<UOffset>.size
preAlign(len: size &+ (prefix ? size : 0), alignment: _minAlignment)
@@ -143,10 +219,15 @@
finished = true
}
- /// starttable will let the builder know, that a new object is being serialized.
+ /// ``startTable(with:)`` will let the builder know, that a new object is being serialized.
///
- /// The function will fatalerror if called while there is another object being serialized
+ /// The function will fatalerror if called while there is another object being serialized.
+ /// ```swift
+ /// let start = Monster
+ /// .startMonster(&fbb)
+ /// ```
/// - Parameter numOfFields: Number of elements to be written to the buffer
+ /// - Returns: Offset of the newly started table
mutating public func startTable(with numOfFields: Int) -> UOffset {
notNested()
isNested = true
@@ -154,11 +235,14 @@
return _bb.size
}
- /// Endtable will let the builder know that the object that's written to it is completed
+ /// ``endTable(at:)`` will let the ``FlatBufferBuilder`` know that the
+ /// object that's written to it is completed
///
- /// This would be called after all the elements are serialized, it will add the vtable into the buffer.
- /// it will fatalError in case the object is called without starttable, or the object has exceeded the limit of
- /// 2GB,
+ /// This would be called after all the elements are serialized,
+ /// it will add the current vtable into the ``ByteBuffer``.
+ /// The functions will `fatalError` in case the object is called
+ /// without ``startTable(with:)``, or the object has exceeded the limit of 2GB.
+ ///
/// - Parameter startOffset:Start point of the object written
/// - returns: The root of the table
mutating public func endTable(at startOffset: UOffset) -> UOffset {
@@ -183,7 +267,10 @@
itr = itr &+ _vtableStorage.size
guard loaded.offset != 0 else { continue }
let _index = (_bb.writerIndex &+ Int(loaded.position))
- _bb.write(value: VOffset(vTableOffset &- loaded.offset), index: _index, direct: true)
+ _bb.write(
+ value: VOffset(vTableOffset &- loaded.offset),
+ index: _index,
+ direct: true)
}
_vtableStorage.clear()
@@ -219,7 +306,7 @@
// MARK: - Builds Buffer
- /// asserts to see if the object is not nested
+ /// Asserts to see if the object is not nested
@usableFromInline
mutating internal func notNested() {
assert(!isNested, "Object serialization must not be nested")
@@ -227,7 +314,7 @@
/// Changes the minimuim alignment of the buffer
/// - Parameter size: size of the current alignment
- @usableFromInline
+ @inline(__always)
mutating internal func minAlignment(size: Int) {
if size > _minAlignment {
_minAlignment = size
@@ -238,8 +325,11 @@
/// - Parameters:
/// - bufSize: Current size of the buffer + the offset of the object to be written
/// - elementSize: Element size
- @usableFromInline
- mutating internal func padding(bufSize: UInt32, elementSize: UInt32) -> UInt32 {
+ @inline(__always)
+ mutating internal func padding(
+ bufSize: UInt32,
+ elementSize: UInt32) -> UInt32
+ {
((~bufSize) &+ 1) & (elementSize - 1)
}
@@ -282,9 +372,20 @@
_vtableStorage.add(loc: FieldLoc(offset: offset, position: position))
}
- // MARK: - Vectors
+ // MARK: - Inserting Vectors
- /// Starts a vector of length and Element size
+ /// ``startVector(_:elementSize:)`` creates a new vector within buffer
+ ///
+ /// The function checks if there is a current object being written, if
+ /// the check passes it creates a buffer alignment of `length * elementSize`
+ /// ```swift
+ /// builder.startVector(
+ /// int32Values.count, elementSize: 4)
+ /// ```
+ ///
+ /// - Parameters:
+ /// - len: Length of vector to be created
+ /// - elementSize: Size of object type to be written
mutating public func startVector(_ len: Int, elementSize: Int) {
notNested()
isNested = true
@@ -292,185 +393,268 @@
preAlign(len: len &* elementSize, alignment: elementSize)
}
- /// Ends the vector of at length
+ /// ``endVector(len:)`` ends the currently created vector
///
- /// The current function will fatalError if startVector is called before serializing the vector
+ /// Calling ``endVector(len:)`` requires the length, of the current
+ /// vector. The length would be pushed to indicate the count of numbers
+ /// within the vector. If ``endVector(len:)`` is called without
+ /// ``startVector(_:elementSize:)`` it asserts.
+ ///
+ /// ```swift
+ /// let vectorOffset = builder.
+ /// endVector(len: int32Values.count)
+ /// ```
+ ///
/// - Parameter len: Length of the buffer
- mutating public func endVector(len: Int) -> UOffset {
+ /// - Returns: Returns the current ``Offset`` in the ``ByteBuffer``
+ mutating public func endVector(len: Int) -> Offset {
assert(isNested, "Calling endVector without calling startVector")
isNested = false
- return push(element: Int32(len))
+ return Offset(offset: push(element: Int32(len)))
}
- /// Creates a vector of type Scalar in the buffer
+ /// Creates a vector of type ``Scalar`` into the ``ByteBuffer``
+ ///
+ /// ``createVector(_:)-4swl0`` writes a vector of type Scalars into
+ /// ``ByteBuffer``. This is a convenient method instead of calling,
+ /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
+ /// ```swift
+ /// let vectorOffset = builder.
+ /// createVector([1, 2, 3, 4])
+ /// ```
+ ///
+ /// The underlying implementation simply calls ``createVector(_:size:)-4lhrv``
+ ///
/// - Parameter elements: elements to be written into the buffer
- /// - returns: Offset of the vector
- mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset<UOffset> {
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset {
createVector(elements, size: elements.count)
}
/// Creates a vector of type Scalar in the buffer
+ ///
+ /// ``createVector(_:)-4swl0`` writes a vector of type Scalars into
+ /// ``ByteBuffer``. This is a convenient method instead of calling,
+ /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
+ /// ```swift
+ /// let vectorOffset = builder.
+ /// createVector([1, 2, 3, 4], size: 4)
+ /// ```
+ ///
/// - Parameter elements: Elements to be written into the buffer
/// - Parameter size: Count of elements
- /// - returns: Offset of the vector
- mutating public func createVector<T: Scalar>(_ elements: [T], size: Int) -> Offset<UOffset> {
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector<T: Scalar>(
+ _ elements: [T],
+ size: Int) -> Offset
+ {
let size = size
startVector(size, elementSize: MemoryLayout<T>.size)
_bb.push(elements: elements)
- return Offset(offset: endVector(len: size))
+ return endVector(len: size)
}
- /// Creates a vector of type Enums in the buffer
+ /// Creates a vector of type ``Enum`` into the ``ByteBuffer``
+ ///
+ /// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into
+ /// ``ByteBuffer``. This is a convenient method instead of calling,
+ /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
+ /// ```swift
+ /// let vectorOffset = builder.
+ /// createVector([.swift, .cpp])
+ /// ```
+ ///
+ /// The underlying implementation simply calls ``createVector(_:size:)-7cx6z``
+ ///
/// - Parameter elements: elements to be written into the buffer
- /// - returns: Offset of the vector
- mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset<UOffset> {
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset {
createVector(elements, size: elements.count)
}
- /// Creates a vector of type Enums in the buffer
+ /// Creates a vector of type ``Enum`` into the ``ByteBuffer``
+ ///
+ /// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into
+ /// ``ByteBuffer``. This is a convenient method instead of calling,
+ /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
+ /// ```swift
+ /// let vectorOffset = builder.
+ /// createVector([.swift, .cpp])
+ /// ```
+ ///
/// - Parameter elements: Elements to be written into the buffer
/// - Parameter size: Count of elements
- /// - returns: Offset of the vector
- mutating public func createVector<T: Enum>(_ elements: [T], size: Int) -> Offset<UOffset> {
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector<T: Enum>(
+ _ elements: [T],
+ size: Int) -> Offset
+ {
let size = size
startVector(size, elementSize: T.byteSize)
for e in elements.reversed() {
_bb.push(value: e.value, len: T.byteSize)
}
- return Offset(offset: endVector(len: size))
+ return endVector(len: size)
}
- /// Creates a vector of type Offsets in the buffer
- /// - Parameter offsets:Array of offsets of type T
- /// - returns: Offset of the vector
- mutating public func createVector<T>(ofOffsets offsets: [Offset<T>]) -> Offset<UOffset> {
+ /// Creates a vector of already written offsets
+ ///
+ /// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into
+ /// ``ByteBuffer``. This is a convenient method instead of calling,
+ /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``.
+ ///
+ /// The underlying implementation simply calls ``createVector(ofOffsets:len:)``
+ ///
+ /// ```swift
+ /// let namesOffsets = builder.
+ /// createVector(ofOffsets: [name1, name2])
+ /// ```
+ /// - Parameter offsets: Array of offsets of type ``Offset``
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector(ofOffsets offsets: [Offset]) -> Offset {
createVector(ofOffsets: offsets, len: offsets.count)
}
- /// Creates a vector of type Offsets in the buffer
- /// - Parameter elements: Array of offsets of type T
+ /// Creates a vector of already written offsets
+ ///
+ /// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into
+ /// ``ByteBuffer``. This is a convenient method instead of calling,
+ /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
+ ///
+ /// ```swift
+ /// let namesOffsets = builder.
+ /// createVector(ofOffsets: [name1, name2])
+ /// ```
+ ///
+ /// - Parameter offsets: Array of offsets of type ``Offset``
/// - Parameter size: Count of elements
- /// - returns: Offset of the vector
- mutating public func createVector<T>(ofOffsets offsets: [Offset<T>], len: Int) -> Offset<UOffset> {
- startVector(len, elementSize: MemoryLayout<Offset<T>>.size)
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector(
+ ofOffsets offsets: [Offset],
+ len: Int) -> Offset
+ {
+ startVector(len, elementSize: MemoryLayout<Offset>.size)
for o in offsets.reversed() {
push(element: o)
}
- return Offset(offset: endVector(len: len))
+ return endVector(len: len)
}
- /// Creates a vector of Strings
- /// - Parameter str: a vector of strings that will be written into the buffer
- /// - returns: Offset of the vector
- mutating public func createVector(ofStrings str: [String]) -> Offset<UOffset> {
- var offsets: [Offset<String>] = []
+ /// Creates a vector of strings
+ ///
+ /// ``createVector(ofStrings:)`` creates a vector of `String` into
+ /// ``ByteBuffer``. This is a convenient method instead of manually
+ /// creating the string offsets, you simply pass it to this function
+ /// and it would write the strings into the ``ByteBuffer``.
+ /// After that it calls ``createVector(ofOffsets:)``
+ ///
+ /// ```swift
+ /// let namesOffsets = builder.
+ /// createVector(ofStrings: ["Name", "surname"])
+ /// ```
+ ///
+ /// - Parameter str: Array of string
+ /// - returns: ``Offset`` of the vector
+ mutating public func createVector(ofStrings str: [String]) -> Offset {
+ var offsets: [Offset] = []
for s in str {
offsets.append(create(string: s))
}
return createVector(ofOffsets: offsets)
}
- /// Creates a vector of Flatbuffer structs.
+ /// Creates a vector of type ``NativeStruct``.
///
- /// The function takes a Type to know what size it is, and alignment
- /// - Parameters:
- /// - structs: An array of UnsafeMutableRawPointer
- /// - type: Type of the struct being written
- /// - returns: Offset of the vector
- @available(
- *,
- deprecated,
- message: "0.9.0 will be removing the following method. Regenerate the code")
- mutating public func createVector<T: Readable>(
- structs: [UnsafeMutableRawPointer],
- type: T.Type) -> Offset<UOffset>
+ /// Any swift struct in the generated code, should confirm to
+ /// ``NativeStruct``. Since the generated swift structs are padded
+ /// to the `FlatBuffers` standards.
+ ///
+ /// ```swift
+ /// let offsets = builder.
+ /// createVector(ofStructs: [NativeStr(num: 1), NativeStr(num: 2)])
+ /// ```
+ ///
+ /// - Parameter structs: A vector of ``NativeStruct``
+ /// - Returns: ``Offset`` of the vector
+ mutating public func createVector<T: NativeStruct>(ofStructs structs: [T])
+ -> Offset
{
- startVector(structs.count &* T.size, elementSize: T.alignment)
+ startVector(
+ structs.count * MemoryLayout<T>.size,
+ elementSize: MemoryLayout<T>.alignment)
for i in structs.reversed() {
- create(struct: i, type: T.self)
+ _ = create(struct: i)
}
- return Offset(offset: endVector(len: structs.count))
- }
-
- /// Starts a vector of struct that considers the size and alignment of the struct
- /// - Parameters:
- /// - count: number of elements to be written
- /// - size: size of struct
- /// - alignment: alignment of the struct
- mutating public func startVectorOfStructs(count: Int, size: Int, alignment: Int) {
- startVector(count &* size, elementSize: alignment)
- }
-
- /// Ends the vector of structs and writtens the current offset
- /// - Parameter count: number of written elements
- /// - Returns: Offset of type UOffset
- mutating public func endVectorOfStructs(count: Int) -> Offset<UOffset> {
- Offset<UOffset>(offset: endVector(len: count))
+ return endVector(len: structs.count)
}
// MARK: - Inserting Structs
- /// Writes a Flatbuffer struct into the buffer
+ /// Writes a ``NativeStruct`` into the ``ByteBuffer``
+ ///
+ /// Adds a native struct that's build and padded according
+ /// to `FlatBuffers` standards. with a predefined position.
+ ///
+ /// ```swift
+ /// let offset = builder.create(
+ /// struct: NativeStr(num: 1),
+ /// position: 10)
+ /// ```
+ ///
/// - Parameters:
- /// - s: Flatbuffer struct
- /// - type: Type of the element to be serialized
- /// - returns: Offset of the Object
- @available(
- *,
- deprecated,
- message: "0.9.0 will be removing the following method. Regenerate the code")
+ /// - s: ``NativeStruct`` to be inserted into the ``ByteBuffer``
+ /// - position: The predefined position of the object
+ /// - Returns: ``Offset`` of written struct
@discardableResult
- mutating public func create<T: Readable>(
- struct s: UnsafeMutableRawPointer,
- type: T.Type) -> Offset<UOffset>
+ mutating public func create<T: NativeStruct>(
+ struct s: T, position: VOffset) -> Offset
{
- let size = T.size
- preAlign(len: size, alignment: T.alignment)
+ let offset = create(struct: s)
+ _vtableStorage.add(loc: FieldLoc(
+ offset: _bb.size,
+ position: VOffset(position)))
+ return offset
+ }
+
+ /// Writes a ``NativeStruct`` into the ``ByteBuffer``
+ ///
+ /// Adds a native struct that's build and padded according
+ /// to `FlatBuffers` standards, directly into the buffer without
+ /// a predefined position.
+ ///
+ /// ```swift
+ /// let offset = builder.create(
+ /// struct: NativeStr(num: 1))
+ /// ```
+ ///
+ /// - Parameters:
+ /// - s: ``NativeStruct`` to be inserted into the ``ByteBuffer``
+ /// - Returns: ``Offset`` of written struct
+ @discardableResult
+ mutating public func create<T: NativeStruct>(
+ struct s: T) -> Offset
+ {
+ let size = MemoryLayout<T>.size
+ preAlign(len: size, alignment: MemoryLayout<T>.alignment)
_bb.push(struct: s, size: size)
return Offset(offset: _bb.size)
}
- /// prepares the ByteBuffer to receive a struct of size and alignment
- /// - Parameters:
- /// - size: size of written struct
- /// - alignment: alignment of written struct
- mutating public func createStructOf(size: Int, alignment: Int) {
- preAlign(len: size, alignment: alignment)
- _bb.prepareBufferToReceiveStruct(of: size)
- }
-
- /// Adds scalars front to back instead of the default behavior of the normal add
- /// - Parameters:
- /// - v: element of type Scalar
- /// - postion: position relative to the `writerIndex`
- mutating public func reverseAdd<T: Scalar>(v: T, postion: Int) {
- _bb.reversePush(
- value: v,
- position: postion,
- len: MemoryLayout<T>.size)
- }
-
- /// Ends the struct and returns the current buffer size
- /// - Returns: Offset of type UOffset
- @discardableResult
- public func endStruct() -> Offset<UOffset> {
- Offset(offset: _bb.size)
- }
-
- /// Adds the offset of a struct into the vTable
- ///
- /// The function fatalErrors if we pass an offset that is out of range
- /// - Parameter o: offset
- mutating public func add(structOffset o: VOffset) {
- _vtableStorage.add(loc: FieldLoc(offset: _bb.size, position: VOffset(o)))
- }
-
// MARK: - Inserting Strings
- /// Insets a string into the buffer using UTF8
+ /// Insets a string into the buffer of type `UTF8`
+ ///
+ /// Adds a swift string into ``ByteBuffer`` by encoding it
+ /// using `UTF8`
+ ///
+ /// ```swift
+ /// let nameOffset = builder
+ /// .create(string: "welcome")
+ /// ```
+ ///
/// - Parameter str: String to be serialized
- /// - returns: The strings offset in the buffer
- mutating public func create(string str: String?) -> Offset<String> {
+ /// - returns: ``Offset`` of inserted string
+ mutating public func create(string str: String?) -> Offset {
guard let str = str else { return Offset() }
let len = str.utf8.count
notNested()
@@ -481,12 +665,26 @@
return Offset(offset: _bb.size)
}
- /// Inserts a shared string to the buffer
+ /// Insets a shared string into the buffer of type `UTF8`
///
- /// The function checks the stringOffsetmap if it's seen a similar string before
+ /// Adds a swift string into ``ByteBuffer`` by encoding it
+ /// using `UTF8`. The function will check if the string,
+ /// is already written to the ``ByteBuffer``
+ ///
+ /// ```swift
+ /// let nameOffset = builder
+ /// .createShared(string: "welcome")
+ ///
+ ///
+ /// let secondOffset = builder
+ /// .createShared(string: "welcome")
+ ///
+ /// assert(nameOffset.o == secondOffset.o)
+ /// ```
+ ///
/// - Parameter str: String to be serialized
- /// - returns: The strings offset in the buffer
- mutating public func createShared(string str: String?) -> Offset<String> {
+ /// - returns: ``Offset`` of inserted string
+ mutating public func createShared(string str: String?) -> Offset {
guard let str = str else { return Offset() }
if let offset = stringOffsetMap[str] {
return offset
@@ -498,37 +696,65 @@
// MARK: - Inseting offsets
- /// Adds the offset of an object into the buffer
+ /// Writes the ``Offset`` of an already written table
+ ///
+ /// Writes the ``Offset`` of a table if not empty into the
+ /// ``ByteBuffer``
+ ///
/// - Parameters:
- /// - offset: Offset of another object to be written
- /// - position: The predefined position of the object
- mutating public func add<T>(offset: Offset<T>, at position: VOffset) {
+ /// - offset: ``Offset`` of another object to be written
+ /// - position: The predefined position of the object
+ mutating public func add(offset: Offset, at position: VOffset) {
if offset.isEmpty { return }
add(element: refer(to: offset.o), def: 0, at: position)
}
- /// Pushes a value of type offset into the buffer
- /// - Parameter o: Offset
- /// - returns: Position of the offset
+ /// Pushes a value of type ``Offset`` into the ``ByteBuffer``
+ /// - Parameter o: ``Offset``
+ /// - returns: Current position of the ``Offset``
@discardableResult
- mutating public func push<T>(element o: Offset<T>) -> UOffset {
+ mutating public func push(element o: Offset) -> UOffset {
push(element: refer(to: o.o))
}
// MARK: - Inserting Scalars to Buffer
- /// Adds a value into the buffer of type Scalar
+ /// Writes a ``Scalar`` value into ``ByteBuffer``
+ ///
+ /// ``add(element:def:at:)`` takes in a default value, and current value
+ /// and the position within the `VTable`. The default value would not
+ /// be serialized if the value is the same as the current value or
+ /// `serializeDefaults` is equal to false.
+ ///
+ /// If serializing defaults is important ``init(initialSize:serializeDefaults:)``,
+ /// passing true for `serializeDefaults` would do the job.
+ ///
+ /// ```swift
+ /// // Adds 10 to the buffer
+ /// builder.add(element: Int(10), def: 1, position 12)
+ /// ```
+ ///
+ /// *NOTE: Never call this manually*
///
/// - Parameters:
/// - element: Element to insert
/// - def: Default value for that element
/// - position: The predefined position of the element
- mutating public func add<T: Scalar>(element: T, def: T, at position: VOffset) {
+ mutating public func add<T: Scalar>(
+ element: T,
+ def: T,
+ at position: VOffset)
+ {
if element == def && !serializeDefaults { return }
track(offset: push(element: element), at: position)
}
- /// Adds a value into the buffer of type optional Scalar
+ /// Writes a optional ``Scalar`` value into ``ByteBuffer``
+ ///
+ /// Takes an optional value to be written into the ``ByteBuffer``
+ ///
+ /// *NOTE: Never call this manually*
+ ///
/// - Parameters:
/// - element: Optional element of type scalar
/// - position: The predefined position of the element
@@ -537,7 +763,10 @@
track(offset: push(element: element), at: position)
}
- /// Pushes the values into the buffer
+ /// Pushes a values of type ``Scalar`` into the ``ByteBuffer``
+ ///
+ /// *NOTE: Never call this manually*
+ ///
/// - Parameter element: Element to insert
/// - returns: Postion of the Element
@discardableResult
@@ -582,12 +811,13 @@
var numOfFields: Int = 0
/// Last written Index
var writtenIndex: Int = 0
- /// the amount of added elements into the buffer
- var addedElements: Int { capacity - (numOfFields &* size) }
/// Creates the memory to store the buffer in
+ @usableFromInline
init() {
- memory = UnsafeMutableRawBufferPointer.allocate(byteCount: 0, alignment: 0)
+ memory = UnsafeMutableRawBufferPointer.allocate(
+ byteCount: 0,
+ alignment: 0)
}
deinit {
@@ -596,6 +826,7 @@
/// Builds a buffer with byte count of fieldloc.size * count of field numbers
/// - Parameter count: number of fields to be written
+ @inline(__always)
func start(count: Int) {
assert(count >= 0, "number of fields should NOT be negative")
let capacity = count &* size
@@ -606,7 +837,9 @@
/// and max offset
/// - Parameter loc: Location of encoded element
func add(loc: FieldLoc) {
- memory.baseAddress?.advanced(by: writtenIndex).storeBytes(of: loc, as: FieldLoc.self)
+ memory.baseAddress?.advanced(by: writtenIndex).storeBytes(
+ of: loc,
+ as: FieldLoc.self)
writtenIndex = writtenIndex &+ size
numOfFields = numOfFields &+ 1
maxOffset = max(loc.position, maxOffset)
@@ -621,16 +854,20 @@
/// Ensure that the buffer has enough space instead of recreating the buffer each time.
/// - Parameter space: space required for the new vtable
+ @inline(__always)
func ensure(space: Int) {
guard space &+ writtenIndex > capacity else { return }
memory.deallocate()
- memory = UnsafeMutableRawBufferPointer.allocate(byteCount: space, alignment: size)
+ memory = UnsafeMutableRawBufferPointer.allocate(
+ byteCount: space,
+ alignment: size)
capacity = space
}
/// Loads an object of type `FieldLoc` from buffer memory
/// - Parameter index: index of element
/// - Returns: a FieldLoc at index
+ @inline(__always)
func load(at index: Int) -> FieldLoc {
memory.load(fromByteOffset: index, as: FieldLoc.self)
}
diff --git a/swift/Sources/FlatBuffers/FlatBufferObject.swift b/swift/Sources/FlatBuffers/FlatBufferObject.swift
index 7536c40..df8ad8d 100644
--- a/swift/Sources/FlatBuffers/FlatBufferObject.swift
+++ b/swift/Sources/FlatBuffers/FlatBufferObject.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,29 +16,49 @@
import Foundation
-/// FlatbufferObject structures all the Flatbuffers objects
-public protocol FlatBufferObject {
- var __buffer: ByteBuffer! { get }
+/// NativeStruct is a protocol that indicates if the struct is a native `swift` struct
+/// since now we will be serializing native structs into the buffer.
+public protocol NativeStruct {}
+
+/// FlatbuffersInitializable is a protocol that allows any object to be
+/// Initialized from a ByteBuffer
+public protocol FlatbuffersInitializable {
+ /// Any flatbuffers object that confirms to this protocol is going to be
+ /// initializable through this initializer
init(_ bb: ByteBuffer, o: Int32)
}
-public protocol ObjectAPI {
+/// FlatbufferObject structures all the Flatbuffers objects
+public protocol FlatBufferObject: FlatbuffersInitializable {
+ var __buffer: ByteBuffer! { get }
+}
+
+/// ``ObjectAPIPacker`` is a protocol that allows object to pack and unpack from a
+/// ``NativeObject`` to a flatbuffers Object and vice versa.
+public protocol ObjectAPIPacker {
+ /// associatedtype to the object that should be unpacked.
associatedtype T
- static func pack(_ builder: inout FlatBufferBuilder, obj: inout T) -> Offset<UOffset>
+
+ /// ``pack(_:obj:)-3ptws`` tries to pacs the variables of a native Object into the `ByteBuffer` by using
+ /// a FlatBufferBuilder
+ /// - Parameters:
+ /// - builder: FlatBufferBuilder that will host incoming data
+ /// - obj: Object of associatedtype to the current implementer
+ ///
+ /// ``pack(_:obj:)-3ptws`` can be called by passing through an already initialized ``FlatBufferBuilder``
+ /// or it can be called by using the public API that will create a new ``FlatBufferBuilder``
+ static func pack(_ builder: inout FlatBufferBuilder, obj: inout T?) -> Offset
+
+ /// ``pack(_:obj:)-20ipk`` packs the variables of a native Object into the `ByteBuffer` by using
+ /// the FlatBufferBuilder
+ /// - Parameters:
+ /// - builder: FlatBufferBuilder that will host incoming data
+ /// - obj: Object of associatedtype to the current implementer
+ ///
+ /// ``pack(_:obj:)-20ipk`` can be called by passing through an already initialized ``FlatBufferBuilder``
+ /// or it can be called by using the public API that will create a new ``FlatBufferBuilder``
+ static func pack(_ builder: inout FlatBufferBuilder, obj: inout T) -> Offset
+
+ /// ``unpack()`` unpacks a ``FlatBuffers`` object into a Native swift object.
mutating func unpack() -> T
}
-
-/// Readable is structures all the Flatbuffers structs
-///
-/// Readable is a procotol that each Flatbuffer struct should confirm to since
-/// FlatBufferBuilder would require a Type to both create(struct:) and createVector(structs:) functions
-public protocol Readable: FlatBufferObject {
- static var size: Int { get }
- static var alignment: Int { get }
-}
-
-public protocol Enum {
- associatedtype T: Scalar
- static var byteSize: Int { get }
- var value: T { get }
-}
diff --git a/swift/Sources/FlatBuffers/FlatBuffersUtils.swift b/swift/Sources/FlatBuffers/FlatBuffersUtils.swift
index 507ef67..dc5f785 100644
--- a/swift/Sources/FlatBuffers/FlatBuffersUtils.swift
+++ b/swift/Sources/FlatBuffers/FlatBuffersUtils.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,8 @@
import Foundation
-public final class FlatBuffersUtils {
+/// FlatBuffersUtils hosts some utility functions that might be useful
+public enum FlatBuffersUtils {
/// Gets the size of the prefix
/// - Parameter bb: Flatbuffer object
@@ -24,8 +25,12 @@
bb.read(def: Int32.self, position: bb.reader)
}
- /// Removes the prefix by duplicating the Flatbuffer
+ /// Removes the prefix by duplicating the Flatbuffer this call is expensive since its
+ /// creates a new buffer use `readPrefixedSizeCheckedRoot` instead
+ /// unless a completely new buffer is required
/// - Parameter bb: Flatbuffer object
+ ///
+ ///
public static func removeSizePrefix(bb: ByteBuffer) -> ByteBuffer {
bb.duplicate(removing: MemoryLayout<Int32>.size)
}
diff --git a/swift/Sources/FlatBuffers/FlatbuffersErrors.swift b/swift/Sources/FlatBuffers/FlatbuffersErrors.swift
new file mode 100644
index 0000000..74c06b9
--- /dev/null
+++ b/swift/Sources/FlatBuffers/FlatbuffersErrors.swift
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// Collection of thrown from the Flatbuffer verifier
+public enum FlatbuffersErrors: Error, Equatable {
+
+ /// Thrown when buffer is bigger than the allowed 2GiB
+ case exceedsMaxSizeAllowed
+ /// Thrown when there is an missaligned pointer at position
+ /// of type
+ case missAlignedPointer(position: Int, type: String)
+ /// Thrown when trying to read a value that goes out of the
+ /// current buffer bounds
+ case outOfBounds(position: UInt, end: Int)
+ /// Thrown when the signed offset is out of the bounds of the
+ /// current buffer
+ case signedOffsetOutOfBounds(offset: Int, position: Int)
+ /// Thrown when a required field doesnt exist within the buffer
+ case requiredFieldDoesntExist(position: VOffset, name: String)
+ /// Thrown when a string is missing its NULL Terminator `\0`,
+ /// this can be disabled in the `VerifierOptions`
+ case missingNullTerminator(position: Int, str: String?)
+ /// Thrown when the verifier has reached the maximum tables allowed,
+ /// this can be disabled in the `VerifierOptions`
+ case maximumTables
+ /// Thrown when the verifier has reached the maximum depth allowed,
+ /// this can be disabled in the `VerifierOptions`
+ case maximumDepth
+ /// Thrown when the verifier is presented with an unknown union case
+ case unknownUnionCase
+ /// thrown when a value for a union is not found within the buffer
+ case valueNotFound(key: Int?, keyName: String, field: Int?, fieldName: String)
+ /// thrown when the size of the keys vector doesnt match fields vector
+ case unionVectorSize(
+ keyVectorSize: Int,
+ fieldVectorSize: Int,
+ unionKeyName: String,
+ fieldName: String)
+ case apparentSizeTooLarge
+
+ public static func == (
+ lhs: FlatbuffersErrors,
+ rhs: FlatbuffersErrors) -> Bool
+ {
+ lhs.localizedDescription == rhs.localizedDescription
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Int+extension.swift b/swift/Sources/FlatBuffers/Int+extension.swift
index ed68ca0..76977ba 100644
--- a/swift/Sources/FlatBuffers/Int+extension.swift
+++ b/swift/Sources/FlatBuffers/Int+extension.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/swift/Sources/FlatBuffers/Message.swift b/swift/Sources/FlatBuffers/Message.swift
index d1db357..eb0bad9 100644
--- a/swift/Sources/FlatBuffers/Message.swift
+++ b/swift/Sources/FlatBuffers/Message.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+import Foundation
+
+/// FlatBufferGRPCMessage protocol that should allow us to invoke
+/// initializers directly from the GRPC generated code
public protocol FlatBufferGRPCMessage {
/// Raw pointer which would be pointing to the beginning of the readable bytes
@@ -27,17 +31,19 @@
/// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the
/// GRPC library
-public final class Message<T: FlatBufferObject>: FlatBufferGRPCMessage {
+public struct Message<T: FlatBufferObject>: FlatBufferGRPCMessage {
internal var buffer: ByteBuffer
/// Returns the an object of type T that would be read from the buffer
public var object: T {
T.init(
buffer,
- o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) + Int32(buffer.reader))
+ o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) +
+ Int32(buffer.reader))
}
- public var rawPointer: UnsafeMutableRawPointer { buffer.memory.advanced(by: buffer.reader) }
+ public var rawPointer: UnsafeMutableRawPointer {
+ buffer.memory.advanced(by: buffer.reader) }
public var size: Int { Int(buffer.size) }
diff --git a/swift/Sources/FlatBuffers/Mutable.swift b/swift/Sources/FlatBuffers/Mutable.swift
index adcaa1f..f77945c 100644
--- a/swift/Sources/FlatBuffers/Mutable.swift
+++ b/swift/Sources/FlatBuffers/Mutable.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,17 +16,17 @@
import Foundation
-/// Mutable is a protocol that allows us to mutate Scalar values within the buffer
+/// Mutable is a protocol that allows us to mutate Scalar values within a ``ByteBuffer``
public protocol Mutable {
/// makes Flatbuffer accessed within the Protocol
var bb: ByteBuffer { get }
- /// makes position of the table/struct accessed within the Protocol
+ /// makes position of the ``Table``/``struct`` accessed within the Protocol
var postion: Int32 { get }
}
extension Mutable {
- /// Mutates the memory in the buffer, this is only called from the access function of table and structs
+ /// Mutates the memory in the buffer, this is only called from the access function of ``Table`` and ``struct``
/// - Parameters:
/// - value: New value to be inserted to the buffer
/// - index: index of the Element
@@ -39,7 +39,7 @@
extension Mutable where Self == Table {
- /// Mutates a value by calling mutate with respect to the position in the table
+ /// Mutates a value by calling mutate with respect to the position in a ``Table``
/// - Parameters:
/// - value: New value to be inserted to the buffer
/// - index: index of the Element
diff --git a/swift/Sources/FlatBuffers/NativeTable.swift b/swift/Sources/FlatBuffers/NativeObject.swift
similarity index 74%
rename from swift/Sources/FlatBuffers/NativeTable.swift
rename to swift/Sources/FlatBuffers/NativeObject.swift
index 5c844c1..bc896e6 100644
--- a/swift/Sources/FlatBuffers/NativeTable.swift
+++ b/swift/Sources/FlatBuffers/NativeObject.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,14 +16,19 @@
import Foundation
-public protocol NativeTable {}
+/// NativeObject is a protocol that all of the `Object-API` generated code should be
+/// conforming to since it allows developers the ease of use to pack and unpack their
+/// Flatbuffers objects
+public protocol NativeObject {}
-extension NativeTable {
+extension NativeObject {
/// Serialize is a helper function that serailizes the data from the Object API to a bytebuffer directly th
/// - Parameter type: Type of the Flatbuffer object
/// - Returns: returns the encoded sized ByteBuffer
- public func serialize<T: ObjectAPI>(type: T.Type) -> ByteBuffer where T.T == Self {
+ public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer
+ where T.T == Self
+ {
var builder = FlatBufferBuilder(initialSize: 1024)
return serialize(builder: &builder, type: type.self)
}
@@ -36,7 +41,10 @@
/// - Returns: returns the encoded sized ByteBuffer
/// - Note: The `serialize(builder:type)` can be considered as a function that allows you to create smaller builder instead of the default `1024`.
/// It can be considered less expensive in terms of memory allocation
- public func serialize<T: ObjectAPI>(builder: inout FlatBufferBuilder, type: T.Type) -> ByteBuffer where T.T == Self {
+ public func serialize<T: ObjectAPIPacker>(
+ builder: inout FlatBufferBuilder,
+ type: T.Type) -> ByteBuffer where T.T == Self
+ {
var s = self
let root = type.pack(&builder, obj: &s)
builder.finish(offset: root)
diff --git a/swift/Sources/FlatBuffers/Offset.swift b/swift/Sources/FlatBuffers/Offset.swift
index 4b42b04..bd3f8a8 100644
--- a/swift/Sources/FlatBuffers/Offset.swift
+++ b/swift/Sources/FlatBuffers/Offset.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@
import Foundation
/// Offset object for all the Objects that are written into the buffer
-public struct Offset<T> {
+public struct Offset {
/// Offset of the object in the buffer
public var o: UOffset
/// Returns false if the offset is equal to zero
diff --git a/swift/Sources/FlatBuffers/Root.swift b/swift/Sources/FlatBuffers/Root.swift
new file mode 100644
index 0000000..4d883b7
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Root.swift
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// Takes in a prefixed sized buffer, where the prefixed size would be skipped.
+/// And would verify that the buffer passed is a valid `Flatbuffers` Object.
+/// - Parameters:
+/// - byteBuffer: Buffer that needs to be checked and read
+/// - options: Verifier options
+/// - Throws: FlatbuffersErrors
+/// - Returns: Returns a valid, checked Flatbuffers object
+///
+/// ``getPrefixedSizeCheckedRoot(byteBuffer:options:)`` would skip the first Bytes in
+/// the ``ByteBuffer`` and verifies the buffer by calling ``getCheckedRoot(byteBuffer:options:)``
+public func getPrefixedSizeCheckedRoot<T: FlatBufferObject & Verifiable>(
+ byteBuffer: inout ByteBuffer,
+ options: VerifierOptions = .init()) throws -> T
+{
+ byteBuffer.skipPrefix()
+ return try getCheckedRoot(byteBuffer: &byteBuffer, options: options)
+}
+
+/// Takes in a prefixed sized buffer, where the prefixed size would be skipped.
+/// Returns a `NON-Checked` flatbuffers object
+/// - Parameter byteBuffer: Buffer that contains data
+/// - Returns: Returns a Flatbuffers object
+///
+/// ``getPrefixedSizeCheckedRoot(byteBuffer:options:)`` would skip the first Bytes in
+/// the ``ByteBuffer`` and then calls ``getRoot(byteBuffer:)``
+public func getPrefixedSizeRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer)
+ -> T
+{
+ byteBuffer.skipPrefix()
+ return getRoot(byteBuffer: &byteBuffer)
+
+}
+
+/// Verifies that the buffer passed is a valid `Flatbuffers` Object.
+/// - Parameters:
+/// - byteBuffer: Buffer that needs to be checked and read
+/// - options: Verifier options
+/// - Throws: FlatbuffersErrors
+/// - Returns: Returns a valid, checked Flatbuffers object
+///
+/// ``getCheckedRoot(byteBuffer:options:)`` Takes in a ``ByteBuffer`` and verifies
+/// that by creating a ``Verifier`` and checkes if all the `Bytes` and correctly aligned
+/// and within the ``ByteBuffer`` range.
+public func getCheckedRoot<T: FlatBufferObject & Verifiable>(
+ byteBuffer: inout ByteBuffer,
+ options: VerifierOptions = .init()) throws -> T
+{
+ var verifier = try Verifier(buffer: &byteBuffer, options: options)
+ try ForwardOffset<T>.verify(&verifier, at: 0, of: T.self)
+ return T.init(
+ byteBuffer,
+ o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) +
+ Int32(byteBuffer.reader))
+}
+
+/// Returns a `NON-Checked` flatbuffers object
+/// - Parameter byteBuffer: Buffer that contains data
+/// - Returns: Returns a Flatbuffers object
+public func getRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) -> T {
+ T.init(
+ byteBuffer,
+ o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) +
+ Int32(byteBuffer.reader))
+}
diff --git a/swift/Sources/FlatBuffers/String+extension.swift b/swift/Sources/FlatBuffers/String+extension.swift
new file mode 100644
index 0000000..2f3168d
--- /dev/null
+++ b/swift/Sources/FlatBuffers/String+extension.swift
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+extension String: Verifiable {
+
+ /// Verifies that the current value is which the bounds of the buffer, and if
+ /// the current `Value` is aligned properly
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Errors coming from `inBuffer`, `missingNullTerminator` and `outOfBounds`
+ public static func verify<T>(
+ _ verifier: inout Verifier,
+ at position: Int,
+ of type: T.Type) throws where T: Verifiable
+ {
+
+ let range = try String.verifyRange(&verifier, at: position, of: UInt8.self)
+ /// Safe &+ since we already check for overflow in verify range
+ let stringLen = range.start &+ range.count
+
+ if stringLen >= verifier.capacity {
+ throw FlatbuffersErrors.outOfBounds(
+ position: UInt(clamping: stringLen.magnitude),
+ end: verifier.capacity)
+ }
+
+ let isNullTerminated = verifier._buffer.read(
+ def: UInt8.self,
+ position: stringLen) == 0
+
+ if !verifier._options._ignoreMissingNullTerminators && !isNullTerminated {
+ let str = verifier._buffer.readString(at: range.start, count: range.count)
+ throw FlatbuffersErrors.missingNullTerminator(
+ position: position,
+ str: str)
+ }
+ }
+}
+
+extension String: FlatbuffersInitializable {
+
+ /// Initailizes a string from a Flatbuffers ByteBuffer
+ /// - Parameters:
+ /// - bb: ByteBuffer containing the readable string
+ /// - o: Current position
+ public init(_ bb: ByteBuffer, o: Int32) {
+ let v = Int(o)
+ let count = bb.read(def: Int32.self, position: v)
+ self = bb.readString(
+ at: MemoryLayout<Int32>.size + v,
+ count: Int(count)) ?? ""
+ }
+}
+
+extension String: ObjectAPIPacker {
+
+ public static func pack(
+ _ builder: inout FlatBufferBuilder,
+ obj: inout String?) -> Offset
+ {
+ guard var obj = obj else { return Offset() }
+ return pack(&builder, obj: &obj)
+ }
+
+ public static func pack(
+ _ builder: inout FlatBufferBuilder,
+ obj: inout String) -> Offset
+ {
+ builder.create(string: obj)
+ }
+
+ public mutating func unpack() -> String {
+ self
+ }
+
+}
+
+extension String: NativeObject {
+
+ public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer
+ where T.T == Self
+ {
+ fatalError("serialize should never be called from string directly")
+ }
+
+ public func serialize<T: ObjectAPIPacker>(
+ builder: inout FlatBufferBuilder,
+ type: T.Type) -> ByteBuffer where T.T == Self
+ {
+ fatalError("serialize should never be called from string directly")
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Struct.swift b/swift/Sources/FlatBuffers/Struct.swift
index 73b3295..ac701d4 100644
--- a/swift/Sources/FlatBuffers/Struct.swift
+++ b/swift/Sources/FlatBuffers/Struct.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,30 @@
import Foundation
+/// Struct is a representation of a mutable `Flatbuffers` struct
+/// since native structs are value types and cant be mutated
+@frozen
public struct Struct {
+
+ /// Hosting Bytebuffer
public private(set) var bb: ByteBuffer
+ /// Current position of the struct
public private(set) var postion: Int32
+ /// Initializer for a mutable flatbuffers struct
+ /// - Parameters:
+ /// - bb: Current hosting Bytebuffer
+ /// - position: Current position for the struct in the ByteBuffer
public init(bb: ByteBuffer, position: Int32 = 0) {
self.bb = bb
postion = position
}
+ /// Reads data from the buffer directly at offset O
+ /// - Parameters:
+ /// - type: Type of data to be read
+ /// - o: Current offset of the data
+ /// - Returns: Data of Type T that conforms to type Scalar
public func readBuffer<T: Scalar>(of type: T.Type, at o: Int32) -> T {
let r = bb.read(def: T.self, position: Int(o + postion))
return r
diff --git a/swift/Sources/FlatBuffers/Table.swift b/swift/Sources/FlatBuffers/Table.swift
index 451398c..ff501fc 100644
--- a/swift/Sources/FlatBuffers/Table.swift
+++ b/swift/Sources/FlatBuffers/Table.swift
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google Inc. All rights reserved.
+ * Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,26 +16,50 @@
import Foundation
+/// `Table` is a Flatbuffers object that can read,
+/// mutate scalar fields within a valid flatbuffers buffer
+@frozen
public struct Table {
+
+ /// Hosting Bytebuffer
public private(set) var bb: ByteBuffer
+ /// Current position of the table within the buffer
public private(set) var postion: Int32
+ /// Initializer for the table interface to allow generated code to read
+ /// data from memory
+ /// - Parameters:
+ /// - bb: ByteBuffer that stores data
+ /// - position: Current table position
+ /// - Note: This will `CRASH` if read on a big endian machine
public init(bb: ByteBuffer, position: Int32 = 0) {
guard isLitteEndian else {
- fatalError("Reading/Writing a buffer in big endian machine is not supported on swift")
+ fatalError(
+ "Reading/Writing a buffer in big endian machine is not supported on swift")
}
self.bb = bb
postion = position
}
+ /// Gets the offset of the current field within the buffer by reading
+ /// the vtable
+ /// - Parameter o: current offset
+ /// - Returns: offset of field within buffer
public func offset(_ o: Int32) -> Int32 {
let vtable = postion - bb.read(def: Int32.self, position: Int(postion))
- return o < bb.read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read(
- def: Int16.self,
- position: Int(vtable + o))) : 0
+ return o < bb
+ .read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read(
+ def: Int16.self,
+ position: Int(vtable + o))) : 0
}
- public func indirect(_ o: Int32) -> Int32 { o + bb.read(def: Int32.self, position: Int(o)) }
+ /// Gets the indirect offset of the current stored object
+ /// (applicable only for object arrays)
+ /// - Parameter o: current offset
+ /// - Returns: offset of field within buffer
+ public func indirect(_ o: Int32) -> Int32 {
+ o + bb.read(def: Int32.self, position: Int(o))
+ }
/// String reads from the buffer with respect to position of the current table.
/// - Parameter offset: Offset of the string
@@ -44,21 +68,22 @@
}
/// Direct string reads from the buffer disregarding the position of the table.
- /// It would be preferable to use string unless the current position of the table is not needed
+ /// It would be preferable to use string unless the current position of the table
+ /// is not needed
/// - Parameter offset: Offset of the string
public func directString(at offset: Int32) -> String? {
var offset = offset
offset += bb.read(def: Int32.self, position: Int(offset))
let count = bb.read(def: Int32.self, position: Int(offset))
- let position = offset + Int32(MemoryLayout<Int32>.size)
- return bb.readString(at: position, count: count)
+ let position = Int(offset) + MemoryLayout<Int32>.size
+ return bb.readString(at: position, count: Int(count))
}
/// Reads from the buffer with respect to the position in the table.
/// - Parameters:
- /// - type: Type of Scalar that needs to be read from the buffer
+ /// - type: Type of Element that needs to be read from the buffer
/// - o: Offset of the Element
- public func readBuffer<T: Scalar>(of type: T.Type, at o: Int32) -> T {
+ public func readBuffer<T>(of type: T.Type, at o: Int32) -> T {
directRead(of: T.self, offset: o + postion)
}
@@ -73,26 +98,37 @@
/// offset: __t.vector(at: offset) + index * 1)
/// ```
/// - Parameters:
- /// - type: Type of Scalar that needs to be read from the buffer
+ /// - type: Type of Element that needs to be read from the buffer
/// - o: Offset of the Element
- public func directRead<T: Scalar>(of type: T.Type, offset o: Int32) -> T {
+ public func directRead<T>(of type: T.Type, offset o: Int32) -> T {
let r = bb.read(def: T.self, position: Int(o))
return r
}
- public func union<T: FlatBufferObject>(_ o: Int32) -> T {
+ /// Returns that current `Union` object at a specific offset
+ /// by adding offset to the current position of table
+ /// - Parameter o: offset
+ /// - Returns: A flatbuffers object
+ public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T {
let o = o + postion
return directUnion(o)
}
- public func directUnion<T: FlatBufferObject>(_ o: Int32) -> T {
+ /// Returns a direct `Union` object at a specific offset
+ /// - Parameter o: offset
+ /// - Returns: A flatbuffers object
+ public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T {
T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o)))
}
+ /// Returns a vector of type T at a specific offset
+ /// This should only be used by `Scalars`
+ /// - Parameter off: Readable offset
+ /// - Returns: Returns a vector of type [T]
public func getVector<T>(at off: Int32) -> [T]? {
let o = offset(off)
guard o != 0 else { return nil }
- return bb.readSlice(index: vector(at: o), count: vector(count: o))
+ return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o)))
}
/// Vector count gets the count of Elements within the array
@@ -113,22 +149,46 @@
o += postion
return o + bb.read(def: Int32.self, position: Int(o)) + 4
}
-}
-extension Table {
+ /// Reading an indirect offset of a table.
+ /// - Parameters:
+ /// - o: position within the buffer
+ /// - fbb: ByteBuffer
+ /// - Returns: table offset
+ static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 {
+ o + fbb.read(def: Int32.self, position: Int(o))
+ }
- static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { o + fbb.read(
- def: Int32.self,
- position: Int(o)) }
-
- static public func offset(_ o: Int32, vOffset: Int32, fbb: ByteBuffer) -> Int32 {
+ /// Gets a vtable value according to an table Offset and a field offset
+ /// - Parameters:
+ /// - o: offset relative to entire buffer
+ /// - vOffset: Field offset within a vtable
+ /// - fbb: ByteBuffer
+ /// - Returns: an position of a field
+ static public func offset(
+ _ o: Int32,
+ vOffset: Int32,
+ fbb: ByteBuffer) -> Int32
+ {
let vTable = Int32(fbb.capacity) - o
return vTable + Int32(fbb.read(
def: Int16.self,
- position: Int(vTable + vOffset - fbb.read(def: Int32.self, position: Int(vTable)))))
+ position: Int(vTable + vOffset - fbb.read(
+ def: Int32.self,
+ position: Int(vTable)))))
}
- static public func compare(_ off1: Int32, _ off2: Int32, fbb: ByteBuffer) -> Int32 {
+ /// Compares two objects at offset A and offset B within a ByteBuffer
+ /// - Parameters:
+ /// - off1: first offset to compare
+ /// - off2: second offset to compare
+ /// - fbb: Bytebuffer
+ /// - Returns: returns the difference between
+ static public func compare(
+ _ off1: Int32,
+ _ off2: Int32,
+ fbb: ByteBuffer) -> Int32
+ {
let memorySize = Int32(MemoryLayout<Int32>.size)
let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2))
@@ -147,7 +207,17 @@
return len1 - len2
}
- static public func compare(_ off1: Int32, _ key: [Byte], fbb: ByteBuffer) -> Int32 {
+ /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer
+ /// - Parameters:
+ /// - off1: Offset to compare to
+ /// - key: bytes array to compare to
+ /// - fbb: Bytebuffer
+ /// - Returns: returns the difference between
+ static public func compare(
+ _ off1: Int32,
+ _ key: [Byte],
+ fbb: ByteBuffer) -> Int32
+ {
let memorySize = Int32(MemoryLayout<Int32>.size)
let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
let len1 = fbb.read(def: Int32.self, position: Int(_off1))
diff --git a/swift/Sources/FlatBuffers/TableVerifier.swift b/swift/Sources/FlatBuffers/TableVerifier.swift
new file mode 100644
index 0000000..42a37f2
--- /dev/null
+++ b/swift/Sources/FlatBuffers/TableVerifier.swift
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// `TableVerifier` verifies a table object is within a provided memory.
+/// It checks if all the objects for a specific generated table, are within
+/// the bounds of the buffer, aligned.
+public struct TableVerifier {
+
+ /// position of current table in `ByteBuffer`
+ fileprivate var _position: Int
+
+ /// Current VTable position
+ fileprivate var _vtable: Int
+
+ /// Length of current VTable
+ fileprivate var _vtableLength: Int
+
+ /// `Verifier` object created in the base verifable call.
+ fileprivate var _verifier: Verifier
+
+ /// Creates a `TableVerifier` verifier that allows the Flatbuffer object
+ /// to verify the buffer before accessing any of the data.
+ ///
+ /// - Parameters:
+ /// - position: Current table Position
+ /// - vtable: Current `VTable` position
+ /// - vtableLength: Current `VTable` length
+ /// - verifier: `Verifier` Object that caches the data of the verifiable object
+ internal init(
+ position: Int,
+ vtable: Int,
+ vtableLength: Int,
+ verifier: inout Verifier)
+ {
+ _position = position
+ _vtable = vtable
+ _vtableLength = vtableLength
+ _verifier = verifier
+ }
+
+ /// Dereference the current object position from the `VTable`
+ /// - Parameter field: Current VTable refrence to position.
+ /// - Throws: A `FlatbuffersErrors` incase the voffset is not aligned/outOfBounds/apparentSizeTooLarge
+ /// - Returns: An optional position for current field
+ internal mutating func dereference(_ field: VOffset) throws -> Int? {
+ if field >= _vtableLength {
+ return nil
+ }
+
+ /// Reading the offset for the field needs to be read.
+ let offset: VOffset = try _verifier.getValue(
+ at: Int(clamping: _vtable &+ Int(field)))
+
+ if offset > 0 {
+ return Int(clamping: _position &+ Int(offset))
+ }
+ return nil
+ }
+
+ /// Visits all the fields within the table to validate the integrity
+ /// of the data
+ /// - Parameters:
+ /// - field: voffset of the current field to be read
+ /// - fieldName: fieldname to report data Errors.
+ /// - required: If the field has to be available in the buffer
+ /// - type: Type of field to be read
+ /// - Throws: A `FlatbuffersErrors` where the field is corrupt
+ public mutating func visit<T>(
+ field: VOffset,
+ fieldName: String,
+ required: Bool,
+ type: T.Type) throws where T: Verifiable
+ {
+ let derefValue = try dereference(field)
+
+ if let value = derefValue {
+ try T.verify(&_verifier, at: value, of: T.self)
+ return
+ }
+ if required {
+ throw FlatbuffersErrors.requiredFieldDoesntExist(
+ position: field,
+ name: fieldName)
+ }
+ }
+
+ /// Visits all the fields for a union object within the table to
+ /// validate the integrity of the data
+ /// - Parameters:
+ /// - key: Current Key Voffset
+ /// - field: Current field Voffset
+ /// - unionKeyName: Union key name
+ /// - fieldName: Field key name
+ /// - required: indicates if an object is required to be present
+ /// - completion: Completion is a handler that WILL be called in the generated
+ /// - Throws: A `FlatbuffersErrors` where the field is corrupt
+ public mutating func visit<T>(
+ unionKey key: VOffset,
+ unionField field: VOffset,
+ unionKeyName: String,
+ fieldName: String,
+ required: Bool,
+ completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
+ where T: UnionEnum
+ {
+ let keyPos = try dereference(key)
+ let valPos = try dereference(field)
+
+ if keyPos == nil && valPos == nil {
+ if required {
+ throw FlatbuffersErrors.requiredFieldDoesntExist(
+ position: key,
+ name: unionKeyName)
+ }
+ return
+ }
+
+ if let _key = keyPos,
+ let _val = valPos
+ {
+ /// verifiying that the key is within the buffer
+ try T.T.verify(&_verifier, at: _key, of: T.T.self)
+ guard let _enum = try T.init(value: _verifier._buffer.read(
+ def: T.T.self,
+ position: _key)) else
+ {
+ throw FlatbuffersErrors.unknownUnionCase
+ }
+ /// we are assuming that Unions will always be of type Uint8
+ try completion(
+ &_verifier,
+ _enum,
+ _val)
+ return
+ }
+ throw FlatbuffersErrors.valueNotFound(
+ key: keyPos,
+ keyName: unionKeyName,
+ field: valPos,
+ fieldName: fieldName)
+ }
+
+ /// Visits and validates all the objects within a union vector
+ /// - Parameters:
+ /// - key: Current Key Voffset
+ /// - field: Current field Voffset
+ /// - unionKeyName: Union key name
+ /// - fieldName: Field key name
+ /// - required: indicates if an object is required to be present
+ /// - completion: Completion is a handler that WILL be called in the generated
+ /// - Throws: A `FlatbuffersErrors` where the field is corrupt
+ public mutating func visitUnionVector<T>(
+ unionKey key: VOffset,
+ unionField field: VOffset,
+ unionKeyName: String,
+ fieldName: String,
+ required: Bool,
+ completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
+ where T: UnionEnum
+ {
+ let keyVectorPosition = try dereference(key)
+ let offsetVectorPosition = try dereference(field)
+
+ if let keyPos = keyVectorPosition,
+ let valPos = offsetVectorPosition
+ {
+ try UnionVector<T>.verify(
+ &_verifier,
+ keyPosition: keyPos,
+ fieldPosition: valPos,
+ unionKeyName: unionKeyName,
+ fieldName: fieldName,
+ completion: completion)
+ return
+ }
+ if required {
+ throw FlatbuffersErrors.requiredFieldDoesntExist(
+ position: field,
+ name: fieldName)
+ }
+ }
+
+ /// Finishs the current Table verifier, and subtracts the current
+ /// table from the incremented depth.
+ public mutating func finish() {
+ _verifier.finish()
+ }
+}
diff --git a/swift/Sources/FlatBuffers/VeriferOptions.swift b/swift/Sources/FlatBuffers/VeriferOptions.swift
new file mode 100644
index 0000000..454dd51
--- /dev/null
+++ b/swift/Sources/FlatBuffers/VeriferOptions.swift
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// `VerifierOptions` is a set of options to verify a flatbuffer
+public struct VerifierOptions {
+
+ /// Maximum `Apparent` size if the buffer can be expanded into a DAG tree
+ internal var _maxApparentSize: UOffset
+
+ /// Maximum table count allowed in a buffer
+ internal var _maxTableCount: UOffset
+
+ /// Maximum depth allowed in a buffer
+ internal var _maxDepth: UOffset
+
+ /// Ignoring missing null terminals in strings
+ internal var _ignoreMissingNullTerminators: Bool
+
+ /// initializes the set of options for the verifier
+ /// - Parameters:
+ /// - maxDepth: Maximum depth allowed in a buffer
+ /// - maxTableCount: Maximum table count allowed in a buffer
+ /// - maxApparentSize: Maximum `Apparent` size if the buffer can be expanded into a DAG tree
+ /// - ignoreMissingNullTerminators: Ignoring missing null terminals in strings *Currently not supported in swift*
+ public init(
+ maxDepth: UOffset = 64,
+ maxTableCount: UOffset = 1000000,
+ maxApparentSize: UOffset = 1 << 31,
+ ignoreMissingNullTerminators: Bool = false)
+ {
+ _maxDepth = maxDepth
+ _maxTableCount = maxTableCount
+ _maxApparentSize = maxApparentSize
+ _ignoreMissingNullTerminators = ignoreMissingNullTerminators
+ }
+
+}
diff --git a/swift/Sources/FlatBuffers/Verifiable.swift b/swift/Sources/FlatBuffers/Verifiable.swift
new file mode 100644
index 0000000..e601cfc
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Verifiable.swift
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// Verifiable is a protocol all swift flatbuffers object should conform to,
+/// since swift is similar to `cpp` and `rust` where the data is read directly
+/// from `unsafeMemory` thus the need to verify if the buffer received is a valid one
+public protocol Verifiable {
+
+ /// Verifies that the current value is which the bounds of the buffer, and if
+ /// the current `Value` is aligned properly
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Errors coming from `inBuffer` function
+ static func verify<T>(
+ _ verifier: inout Verifier,
+ at position: Int,
+ of type: T.Type) throws where T: Verifiable
+}
+
+extension Verifiable {
+
+ /// Verifies if the current range to be read is within the bounds of the buffer,
+ /// and if the range is properly aligned
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Erros thrown from `isAligned` & `rangeInBuffer`
+ /// - Returns: a tuple of the start position and the count of objects within the range
+ @discardableResult
+ public static func verifyRange<T>(
+ _ verifier: inout Verifier,
+ at position: Int, of type: T.Type) throws -> (start: Int, count: Int)
+ {
+ let len: UOffset = try verifier.getValue(at: position)
+ let intLen = Int(len)
+ let start = Int(clamping: (position &+ MemoryLayout<Int32>.size).magnitude)
+ try verifier.isAligned(position: start, type: type.self)
+ try verifier.rangeInBuffer(position: start, size: intLen)
+ return (start, intLen)
+ }
+}
+
+extension Verifiable where Self: Scalar {
+
+ /// Verifies that the current value is which the bounds of the buffer, and if
+ /// the current `Value` is aligned properly
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Errors coming from `inBuffer` function
+ public static func verify<T>(
+ _ verifier: inout Verifier,
+ at position: Int,
+ of type: T.Type) throws where T: Verifiable
+ {
+ try verifier.inBuffer(position: position, of: type.self)
+ }
+}
+
+// MARK: - ForwardOffset
+
+/// ForwardOffset is a container to wrap around the Generic type to be verified
+/// from the flatbuffers object.
+public enum ForwardOffset<U>: Verifiable where U: Verifiable {
+
+ /// Verifies that the current value is which the bounds of the buffer, and if
+ /// the current `Value` is aligned properly
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Errors coming from `inBuffer` function
+ public static func verify<T>(
+ _ verifier: inout Verifier,
+ at position: Int,
+ of type: T.Type) throws where T: Verifiable
+ {
+ let offset: UOffset = try verifier.getValue(at: position)
+ let nextOffset = Int(clamping: (Int(offset) &+ position).magnitude)
+ try U.verify(&verifier, at: nextOffset, of: U.self)
+ }
+}
+
+// MARK: - Vector
+
+/// Vector is a container to wrap around the Generic type to be verified
+/// from the flatbuffers object.
+public enum Vector<U, S>: Verifiable where U: Verifiable, S: Verifiable {
+
+ /// Verifies that the current value is which the bounds of the buffer, and if
+ /// the current `Value` is aligned properly
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - position: Current position within the buffer
+ /// - type: The type of the object to be verified
+ /// - Throws: Errors coming from `inBuffer` function
+ public static func verify<T>(
+ _ verifier: inout Verifier,
+ at position: Int,
+ of type: T.Type) throws where T: Verifiable
+ {
+ /// checks if the next verification type S is equal to U of type forwardOffset
+ /// This had to be done since I couldnt find a solution for duplicate call functions
+ /// A fix will be appreciated
+ if U.self is ForwardOffset<S>.Type {
+ let range = try verifyRange(&verifier, at: position, of: UOffset.self)
+ for index in stride(
+ from: range.start,
+ to: Int(clamping: range.start &+ range.count),
+ by: MemoryLayout<UOffset>.size)
+ {
+ try U.verify(&verifier, at: index, of: U.self)
+ }
+ } else {
+ try S.verifyRange(&verifier, at: position, of: S.self)
+ }
+ }
+}
+
+// MARK: - UnionVector
+
+/// UnionVector is a container to wrap around the Generic type to be verified
+/// from the flatbuffers object.
+public enum UnionVector<S> where S: UnionEnum {
+
+ /// Completion handler for the function Verify, that passes the verifier
+ /// enum type and position of union field
+ public typealias Completion = (inout Verifier, S, Int) throws -> Void
+
+ /// Verifies if the current range to be read is within the bounds of the buffer,
+ /// and if the range is properly aligned. It also verifies if the union type is a
+ /// *valid/supported* union type.
+ /// - Parameters:
+ /// - verifier: Verifier that hosts the buffer
+ /// - keyPosition: Current union key position within the buffer
+ /// - fieldPosition: Current union field position within the buffer
+ /// - unionKeyName: Name of key to written if error is presented
+ /// - fieldName: Name of field to written if error is presented
+ /// - completion: Completion is a handler that WILL be called in the generated
+ /// code to verify the actual objects
+ /// - Throws: FlatbuffersErrors
+ public static func verify(
+ _ verifier: inout Verifier,
+ keyPosition: Int,
+ fieldPosition: Int,
+ unionKeyName: String,
+ fieldName: String,
+ completion: @escaping Completion) throws
+ {
+ /// Get offset for union key vectors and offset vectors
+ let keyOffset: UOffset = try verifier.getValue(at: keyPosition)
+ let fieldOffset: UOffset = try verifier.getValue(at: fieldPosition)
+
+ /// Check if values are within the buffer, returns the start position of vectors, and vector counts
+ /// Using &+ is safe since we already verified that the value is within the buffer, where the max is
+ /// going to be 2Gib and swift supports Int64 by default
+ let keysRange = try S.T.verifyRange(
+ &verifier,
+ at: Int(keyOffset) &+ keyPosition,
+ of: S.T.self)
+ let offsetsRange = try UOffset.verifyRange(
+ &verifier,
+ at: Int(fieldOffset) &+ fieldPosition,
+ of: UOffset.self)
+
+ guard keysRange.count == offsetsRange.count else {
+ throw FlatbuffersErrors.unionVectorSize(
+ keyVectorSize: keysRange.count,
+ fieldVectorSize: offsetsRange.count,
+ unionKeyName: unionKeyName,
+ fieldName: fieldName)
+ }
+
+ var count = 0
+ /// Iterate over the vector of keys and offsets.
+ while count < keysRange.count {
+
+ /// index of readable enum value in array
+ let keysIndex = MemoryLayout<S.T>.size * count
+ guard let _enum = try S.init(value: verifier._buffer.read(
+ def: S.T.self,
+ position: keysRange.start + keysIndex)) else
+ {
+ throw FlatbuffersErrors.unknownUnionCase
+ }
+ /// index of readable offset value in array
+ let fieldIndex = MemoryLayout<UOffset>.size * count
+ try completion(&verifier, _enum, offsetsRange.start + fieldIndex)
+ count += 1
+ }
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Verifier.swift b/swift/Sources/FlatBuffers/Verifier.swift
new file mode 100644
index 0000000..6f65ce7
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Verifier.swift
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Foundation
+
+/// Verifier that check if the buffer passed into it is a valid,
+/// safe, aligned Flatbuffers object since swift read from `unsafeMemory`
+public struct Verifier {
+
+ /// Flag to check for alignment if true
+ fileprivate let _checkAlignment: Bool
+ /// Capacity of the current buffer
+ fileprivate var _capacity: Int
+ /// Current ApparentSize
+ fileprivate var _apparentSize: UOffset = 0
+ /// Amount of tables present within a buffer
+ fileprivate var _tableCount = 0
+
+ /// Capacity of the buffer
+ internal var capacity: Int { _capacity }
+ /// Current reached depth within the buffer
+ internal var _depth = 0
+ /// Current verifiable ByteBuffer
+ internal var _buffer: ByteBuffer
+ /// Options for verification
+ internal let _options: VerifierOptions
+
+ /// Initializer for the verifier
+ /// - Parameters:
+ /// - buffer: Bytebuffer that is required to be verified
+ /// - options: `VerifierOptions` that set the rule for some of the verification done
+ /// - checkAlignment: If alignment check is required to be preformed
+ /// - Throws: `exceedsMaxSizeAllowed` if capacity of the buffer is more than 2GiB
+ public init(
+ buffer: inout ByteBuffer,
+ options: VerifierOptions = .init(),
+ checkAlignment: Bool = true) throws
+ {
+ guard buffer.capacity < FlatBufferMaxSize else {
+ throw FlatbuffersErrors.exceedsMaxSizeAllowed
+ }
+
+ _buffer = buffer
+ _capacity = buffer.capacity
+ _checkAlignment = checkAlignment
+ _options = options
+ }
+
+ /// Resets the verifier to initial state
+ public mutating func reset() {
+ _depth = 0
+ _tableCount = 0
+ }
+
+ /// Checks if the value of type `T` is aligned properly in the buffer
+ /// - Parameters:
+ /// - position: Current position
+ /// - type: Type of value to check
+ /// - Throws: `missAlignedPointer` if the pointer is not aligned properly
+ public mutating func isAligned<T>(position: Int, type: T.Type) throws {
+
+ /// If check alignment is false this mutating function doesnt continue
+ if !_checkAlignment { return }
+
+ /// advance pointer to position X
+ let ptr = _buffer._storage.memory.advanced(by: position)
+ /// Check if the pointer is aligned
+ if Int(bitPattern: ptr) & (MemoryLayout<T>.alignment &- 1) == 0 {
+ return
+ }
+
+ throw FlatbuffersErrors.missAlignedPointer(
+ position: position,
+ type: String(describing: T.self))
+ }
+
+ /// Checks if the value of Size "X" is within the range of the buffer
+ /// - Parameters:
+ /// - position: Current postion to be read
+ /// - size: `Byte` Size of readable object within the buffer
+ /// - Throws: `outOfBounds` if the value is out of the bounds of the buffer
+ /// and `apparentSizeTooLarge` if the apparent size is bigger than the one specified
+ /// in `VerifierOptions`
+ public mutating func rangeInBuffer(position: Int, size: Int) throws {
+ let end = UInt(clamping: (position &+ size).magnitude)
+ if end > _buffer.capacity {
+ throw FlatbuffersErrors.outOfBounds(position: end, end: capacity)
+ }
+ _apparentSize = _apparentSize &+ UInt32(size)
+ if _apparentSize > _options._maxApparentSize {
+ throw FlatbuffersErrors.apparentSizeTooLarge
+ }
+ }
+
+ /// Validates if a value of type `T` is aligned and within the bounds of
+ /// the buffer
+ /// - Parameters:
+ /// - position: Current readable position
+ /// - type: Type of value to check
+ /// - Throws: FlatbuffersErrors
+ public mutating func inBuffer<T>(position: Int, of type: T.Type) throws {
+ try isAligned(position: position, type: type)
+ try rangeInBuffer(position: position, size: MemoryLayout<T>.size)
+ }
+
+ /// Visits a table at the current position and validates if the table meets
+ /// the rules specified in the `VerifierOptions`
+ /// - Parameter position: Current position to be read
+ /// - Throws: FlatbuffersErrors
+ /// - Returns: A `TableVerifier` at the current readable table
+ public mutating func visitTable(at position: Int) throws -> TableVerifier {
+ let vtablePosition = try derefOffset(position: position)
+ let vtableLength: VOffset = try getValue(at: vtablePosition)
+
+ let length = Int(vtableLength)
+ try isAligned(
+ position: Int(clamping: (vtablePosition + length).magnitude),
+ type: VOffset.self)
+ try rangeInBuffer(position: vtablePosition, size: length)
+
+ _tableCount += 1
+
+ if _tableCount > _options._maxTableCount {
+ throw FlatbuffersErrors.maximumTables
+ }
+
+ _depth += 1
+
+ if _depth > _options._maxDepth {
+ throw FlatbuffersErrors.maximumDepth
+ }
+
+ return TableVerifier(
+ position: position,
+ vtable: vtablePosition,
+ vtableLength: length,
+ verifier: &self)
+ }
+
+ /// Validates if a value of type `T` is within the buffer and returns it
+ /// - Parameter position: Current position to be read
+ /// - Throws: `inBuffer` errors
+ /// - Returns: a value of type `T` usually a `VTable` or a table offset
+ internal mutating func getValue<T>(at position: Int) throws -> T {
+ try inBuffer(position: position, of: T.self)
+ return _buffer.read(def: T.self, position: position)
+ }
+
+ /// derefrences an offset within a vtable to get the position of the field
+ /// in the bytebuffer
+ /// - Parameter position: Current readable position
+ /// - Throws: `inBuffer` errors & `signedOffsetOutOfBounds`
+ /// - Returns: Current readable position for a field
+ @inline(__always)
+ internal mutating func derefOffset(position: Int) throws -> Int {
+ try inBuffer(position: position, of: Int32.self)
+
+ let offset = _buffer.read(def: Int32.self, position: position)
+ // switching to int32 since swift's default Int is int64
+ // this should be safe since we already checked if its within
+ // the buffer
+ let _int32Position = UInt32(position)
+
+ let reportedOverflow: (partialValue: UInt32, overflow: Bool)
+ if offset > 0 {
+ reportedOverflow = _int32Position
+ .subtractingReportingOverflow(offset.magnitude)
+ } else {
+ reportedOverflow = _int32Position
+ .addingReportingOverflow(offset.magnitude)
+ }
+
+ /// since `subtractingReportingOverflow` & `addingReportingOverflow` returns true,
+ /// if there is overflow we return failure
+ if reportedOverflow.overflow || reportedOverflow.partialValue > _buffer
+ .capacity
+ {
+ throw FlatbuffersErrors.signedOffsetOutOfBounds(
+ offset: Int(offset),
+ position: position)
+ }
+
+ return Int(reportedOverflow.partialValue)
+ }
+
+ /// finishes the current iteration of verification on an object
+ internal mutating func finish() {
+ _depth -= 1
+ }
+}