Skip to content

Commit

Permalink
Adds implementation flag for swift (#7202)
Browse files Browse the repository at this point in the history
* Adds implementation flag for swift

Forces internal flag when using @_implementationOnly in swift

Fixes access type for verifier functions & encoder functions

Updates generated code

* Addresses PR comments & adds a code gen dir within the swift tests

* Adds test case for no-include

* Fixes code gen script

Removes prefix
  • Loading branch information
mustiikhalil authored Apr 6, 2022
1 parent 1461569 commit 832c618
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 8 deletions.
2 changes: 2 additions & 0 deletions include/flatbuffers/idl.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ struct IDLOptions {
bool output_enum_identifiers;
bool prefixed_enums;
bool scoped_enums;
bool swift_implementation_only;
bool include_dependence_headers;
bool mutable_buffer;
bool one_file;
Expand Down Expand Up @@ -658,6 +659,7 @@ struct IDLOptions {
output_enum_identifiers(true),
prefixed_enums(true),
scoped_enums(false),
swift_implementation_only(false),
include_dependence_headers(true),
mutable_buffer(false),
one_file(false),
Expand Down
19 changes: 19 additions & 0 deletions scripts/generate_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@

# Specify the other paths that will be referenced
tests_path = Path(root_path, "tests")
swift_code_gen = Path(root_path, "tests/FlatBuffers.Test.Swift/CodeGenerationTests")
samples_path = Path(root_path, "samples")
reflection_path = Path(root_path, "reflection")

Expand Down Expand Up @@ -138,6 +139,12 @@ def glob(path, pattern):
TS_OPTS = ["--ts", "--gen-name-strings"]
LOBSTER_OPTS = ["--lobster"]
SWIFT_OPTS = ["--swift", "--gen-json-emit", "--bfbs-filenames", str(tests_path)]
SWIFT_OPTS_CODE_GEN = [
"--swift",
"--gen-json-emit",
"--bfbs-filenames",
swift_code_gen
]
JAVA_OPTS = ["--java"]
KOTLIN_OPTS = ["--kotlin"]
PHP_OPTS = ["--php"]
Expand Down Expand Up @@ -380,6 +387,18 @@ def glob(path, pattern):
prefix=swift_prefix,
)

flatc(
SWIFT_OPTS_CODE_GEN + BASE_OPTS + ["--grpc", "--swift-implementation-only"],
schema="test_import.fbs",
cwd=swift_code_gen
)

flatc(
SWIFT_OPTS_CODE_GEN + NO_INCL_OPTS + ["--grpc"],
schema="test_no_include.fbs",
cwd=swift_code_gen
)

# --filename-suffix and --filename-ext tests
flatc(
CPP_OPTS + NO_INCL_OPTS + ["--filename-suffix", "_suffix", "--filename-ext", "hpp"],
Expand Down
4 changes: 4 additions & 0 deletions src/flatc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ const static FlatCOption options[] = {
{ "", "scoped-enums", "",
"Use C++11 style scoped and strongly typed enums. Also implies "
"--no-prefix." },
{ "", "swift-implementation-only", "",
"Adds a @_implementationOnly to swift imports" },
{ "", "gen-inclues", "",
"(deprecated), this is the default behavior. If the original behavior is "
"required (no include statements) use --no-includes." },
Expand Down Expand Up @@ -490,6 +492,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
opts.java_checkerframework = true;
} else if (arg == "--gen-generated") {
opts.gen_generated = true;
} else if (arg == "--swift-implementation-only") {
opts.swift_implementation_only = true;
} else if (arg == "--gen-json-emit") {
opts.gen_json_coders = true;
} else if (arg == "--object-prefix") {
Expand Down
19 changes: 14 additions & 5 deletions src/idl_gen_swift.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ class SwiftGenerator : public BaseGenerator {
code_ += "// " + std::string(FlatBuffersGeneratedWarning());
code_ += "// swiftlint:disable all";
code_ += "// swiftformat:disable all\n";
if (parser_.opts.include_dependence_headers || parser_.opts.generate_all)
if (parser_.opts.include_dependence_headers || parser_.opts.generate_all) {
if (parser_.opts.swift_implementation_only)
code_ += "@_implementationOnly \\";

code_ += "import FlatBuffers\n";
}

// Generate code for all the enum declarations.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
Expand Down Expand Up @@ -212,6 +216,7 @@ class SwiftGenerator : public BaseGenerator {
// Generates the reader for swift
void GenStructReader(const StructDef &struct_def) {
const bool is_private_access =
parser_.opts.swift_implementation_only ||
struct_def.attributes.Lookup("private") != nullptr;
code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
GenComment(struct_def.doc_comment);
Expand Down Expand Up @@ -286,7 +291,8 @@ class SwiftGenerator : public BaseGenerator {
}
code_ += "";
code_ +=
"public static func verify<T>(_ verifier: inout Verifier, at position: "
"{{ACCESS_TYPE}} static func verify<T>(_ verifier: inout Verifier, at "
"position: "
"Int, of type: T.Type) throws where T: Verifiable {";
Indent();
code_ +=
Expand Down Expand Up @@ -371,6 +377,7 @@ class SwiftGenerator : public BaseGenerator {
// Generates the create function for swift
void GenStructWriter(const StructDef &struct_def) {
const bool is_private_access =
parser_.opts.swift_implementation_only ||
struct_def.attributes.Lookup("private") != nullptr;
code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
Expand Down Expand Up @@ -440,6 +447,7 @@ class SwiftGenerator : public BaseGenerator {
// Generates the reader for swift
void GenTable(const StructDef &struct_def) {
const bool is_private_access =
parser_.opts.swift_implementation_only ||
struct_def.attributes.Lookup("private") != nullptr;
code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
GenObjectHeader(struct_def);
Expand Down Expand Up @@ -699,7 +707,7 @@ class SwiftGenerator : public BaseGenerator {
field.value.type.struct_def->fixed) &&
(IsVector(field.value.type) || IsArray(field.value.type))) {
const auto field_name = namer_.NamespacedType(*vectortype.struct_def);
code_ += "public static func " +
code_ += "{{ACCESS_TYPE}} static func " +
namer_.Method("start_vector_of", field_var) +
"(_ size: Int, in builder: inout "
"FlatBufferBuilder) {";
Expand Down Expand Up @@ -1054,7 +1062,7 @@ class SwiftGenerator : public BaseGenerator {
code_ += "";
if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def);

code_ += "public func encode(to encoder: Encoder) throws {";
code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
Indent();
if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def);
Outdent();
Expand All @@ -1066,7 +1074,8 @@ class SwiftGenerator : public BaseGenerator {

void GenerateVerifier(const StructDef &struct_def) {
code_ +=
"public static func verify<T>(_ verifier: inout Verifier, at position: "
"{{ACCESS_TYPE}} static func verify<T>(_ verifier: inout Verifier, at "
"position: "
"Int, of type: T.Type) throws where T: Verifiable {";
Indent();
code_ += "var _v = try verifier.visitTable(at: position)";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
table Message {
internal_message: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// automatically generated by the FlatBuffers compiler, do not modify
// swiftlint:disable all
// swiftformat:disable all

@_implementationOnly import FlatBuffers

internal struct Message: FlatBufferObject, Verifiable, ObjectAPIPacker {

static func validateVersion() { FlatBuffersVersion_2_0_0() }
internal var __buffer: ByteBuffer! { return _accessor.bb }
private var _accessor: Table

internal static func getRootAsMessage(bb: ByteBuffer) -> Message { return Message(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }

private init(_ t: Table) { _accessor = t }
internal init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }

private enum VTOFFSET: VOffset {
case internalMessage = 4
var v: Int32 { Int32(self.rawValue) }
var p: VOffset { self.rawValue }
}

internal var internalMessage: String? { let o = _accessor.offset(VTOFFSET.internalMessage.v); return o == 0 ? nil : _accessor.string(at: o) }
internal var internalMessageSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.internalMessage.v) }
internal static func startMessage(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
internal static func add(internalMessage: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: internalMessage, at: VTOFFSET.internalMessage.p) }
internal static func endMessage(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
internal static func createMessage(
_ fbb: inout FlatBufferBuilder,
internalMessageOffset internalMessage: Offset = Offset()
) -> Offset {
let __start = Message.startMessage(&fbb)
Message.add(internalMessage: internalMessage, &fbb)
return Message.endMessage(&fbb, start: __start)
}


internal mutating func unpack() -> MessageT {
return MessageT(&self)
}
internal static func pack(_ builder: inout FlatBufferBuilder, obj: inout MessageT?) -> Offset {
guard var obj = obj else { return Offset() }
return pack(&builder, obj: &obj)
}

internal static func pack(_ builder: inout FlatBufferBuilder, obj: inout MessageT) -> Offset {
let __internalMessage: Offset
if let s = obj.internalMessage {
__internalMessage = builder.create(string: s)
} else {
__internalMessage = Offset()
}

let __root = Message.startMessage(&builder)
Message.add(internalMessage: __internalMessage, &builder)
return Message.endMessage(&builder, start: __root)
}

internal static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.internalMessage.p, fieldName: "internalMessage", required: false, type: ForwardOffset<String>.self)
_v.finish()
}
}

extension Message: Encodable {

enum CodingKeys: String, CodingKey {
case internalMessage = "internal_message"
}
internal func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(internalMessage, forKey: .internalMessage)
}
}

internal class MessageT: NativeObject {

internal var internalMessage: String?

internal init(_ _t: inout Message) {
internalMessage = _t.internalMessage
}

internal init() {
}

internal func serialize() -> ByteBuffer { return serialize(type: Message.self) }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
table Message {
internal_message: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// automatically generated by the FlatBuffers compiler, do not modify
// swiftlint:disable all
// swiftformat:disable all

public struct Message: FlatBufferObject, Verifiable, ObjectAPIPacker {

static func validateVersion() { FlatBuffersVersion_2_0_0() }
public var __buffer: ByteBuffer! { return _accessor.bb }
private var _accessor: Table

public static func getRootAsMessage(bb: ByteBuffer) -> Message { return Message(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }

private init(_ t: Table) { _accessor = t }
public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }

private enum VTOFFSET: VOffset {
case internalMessage = 4
var v: Int32 { Int32(self.rawValue) }
var p: VOffset { self.rawValue }
}

public var internalMessage: String? { let o = _accessor.offset(VTOFFSET.internalMessage.v); return o == 0 ? nil : _accessor.string(at: o) }
public var internalMessageSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.internalMessage.v) }
public static func startMessage(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
public static func add(internalMessage: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: internalMessage, at: VTOFFSET.internalMessage.p) }
public static func endMessage(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
public static func createMessage(
_ fbb: inout FlatBufferBuilder,
internalMessageOffset internalMessage: Offset = Offset()
) -> Offset {
let __start = Message.startMessage(&fbb)
Message.add(internalMessage: internalMessage, &fbb)
return Message.endMessage(&fbb, start: __start)
}


public mutating func unpack() -> MessageT {
return MessageT(&self)
}
public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MessageT?) -> Offset {
guard var obj = obj else { return Offset() }
return pack(&builder, obj: &obj)
}

public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MessageT) -> Offset {
let __internalMessage: Offset
if let s = obj.internalMessage {
__internalMessage = builder.create(string: s)
} else {
__internalMessage = Offset()
}

let __root = Message.startMessage(&builder)
Message.add(internalMessage: __internalMessage, &builder)
return Message.endMessage(&builder, start: __root)
}

public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.internalMessage.p, fieldName: "internalMessage", required: false, type: ForwardOffset<String>.self)
_v.finish()
}
}

extension Message: Encodable {

enum CodingKeys: String, CodingKey {
case internalMessage = "internal_message"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(internalMessage, forKey: .internalMessage)
}
}

public class MessageT: NativeObject {

public var internalMessage: String?

public init(_ _t: inout Message) {
internalMessage = _t.internalMessage
}

public init() {
}

public func serialize() -> ByteBuffer { return serialize(type: Message.self) }

}
8 changes: 7 additions & 1 deletion tests/FlatBuffers.Test.Swift/SwiftTest.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
swift_dir=`pwd`
cd ..
test_dir=`pwd`
alias fbc='${test_dir}/../flatc'
alias fbc='${test_dir}/../Debug/flatc'
shopt -s expand_aliases

cd ${swift_dir}/Tests/FlatBuffers.Test.SwiftTests
Expand All @@ -11,6 +11,12 @@ fbc --swift --gen-json-emit --gen-object-api ${test_dir}/more_defaults.fbs
fbc --swift --gen-json-emit --gen-mutable --gen-object-api ${test_dir}/MutatingBool.fbs
cd ${swift_dir}

# Goes into the code generation tests
cd CodeGenerationTests
fbc --swift --gen-mutable --grpc --gen-json-emit --gen-object-api --swift-implementation-only test_import.fbs
fbc --swift --gen-mutable --grpc --gen-json-emit --gen-object-api --no-includes test_no_include.fbs
cd ..

cd ${swift_dir}/Sources/SwiftFlatBuffers
# create better fuzzing test file
fbc --swift --gen-json-emit fuzzer.fbs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ internal struct MyGame_Example_TestSimpleTableWithEnum: FlatBufferObject, Verifi
return MyGame_Example_TestSimpleTableWithEnum.endTestSimpleTableWithEnum(&builder, start: __root)
}

public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
internal static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.color.p, fieldName: "color", required: false, type: MyGame_Example_Color.self)
_v.finish()
Expand All @@ -842,7 +842,7 @@ extension MyGame_Example_TestSimpleTableWithEnum: Encodable {
enum CodingKeys: String, CodingKey {
case color = "color"
}
public func encode(to encoder: Encoder) throws {
internal func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if color != .green {
try container.encodeIfPresent(color, forKey: .color)
Expand Down

0 comments on commit 832c618

Please sign in to comment.