Skip to content

Commit 3fd4d16

Browse files
committed
Fixes mutations within fixed sizes arrays
1 parent 70318f0 commit 3fd4d16

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

src/idl_gen_swift.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,9 +428,21 @@ class SwiftGenerator : public BaseGenerator {
428428
GenConstructor("{{ACCESS}}.position + {{OFFSET}}");
429429
}
430430

431-
if (parser_.opts.mutable_buffer && !IsStruct(field.value.type) &&
432-
!IsArray(field.value.type))
433-
code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type));
431+
if (parser_.opts.mutable_buffer) {
432+
if (!IsStruct(field.value.type) && !IsArray(field.value.type)) {
433+
code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type));
434+
} else if (IsArray(field.value.type) &&
435+
!IsStruct(field.value.type.VectorType())) {
436+
code_.SetValue("IS_RAW", IsEnum(field.value.type.VectorType())
437+
? ".rawValue"
438+
: "");
439+
code_ +=
440+
"@discardableResult {{ACCESS_TYPE}} func mutate({{FIELDVAR}}: "
441+
"{{VALUETYPE}}, at index: Int32) -> Bool { "
442+
"return {{ACCESS}}.mutate({{FIELDVAR}}{{IS_RAW}}, index: "
443+
"{{OFFSET_VALUE}} + (index * {{SIZE}})) }";
444+
}
445+
}
434446
}
435447

436448
if (parser_.opts.generate_object_based_api) {

tests/swift/Tests/Flatbuffers/FlatBuffersArraysTests.swift

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
// Created by Gwen on 2025-11-04.
66
//
77

8+
#if compiler(>=6.2)
9+
810
import XCTest
911

1012
@testable import FlatBuffers
1113

1214
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, *)
1315
final class FlatBuffersArraysTests: XCTestCase {
14-
16+
1517
func testGoldenData() throws {
1618
// swiftformat:disable all
1719
let data: [UInt8] = [
@@ -27,9 +29,9 @@ final class FlatBuffersArraysTests: XCTestCase {
2729
255, 255, 255, 255, 255, 255, 127
2830
]
2931
// swiftformat:enable all
30-
32+
3133
var builder = FlatBufferBuilder(initialSize: 1024)
32-
34+
3335
let nestedStruct1 = MyGame_Example_NestedStruct(
3436
a: [-1, 2],
3537
b: .a,
@@ -52,22 +54,22 @@ final class FlatBuffersArraysTests: XCTestCase {
5254
e: 1,
5355
f: [-0x8000000000000000, 0x7FFFFFFFFFFFFFFF]
5456
)
55-
57+
5658
let arrayTable = MyGame_Example_ArrayTable.createArrayTable(&builder, a: arrayStruct)
5759
builder.finish(offset: arrayTable, fileId: "ARRT")
58-
60+
5961
let array = builder.sizedByteArray
60-
62+
6163
XCTAssertEqual(data, array)
62-
64+
6365
var buf = ByteBuffer(bytes: array)
6466
let table: MyGame_Example_ArrayTable = try getCheckedRoot(byteBuffer: &buf, fileId: "ARRT")
65-
verify(a: table.a)
66-
mutate(table: table)
67-
verify(a: table.a)
67+
testNativeStruct(a: table.a)
68+
testMutations(in: table)
69+
testNativeStruct(a: table.a)
6870
}
69-
70-
func verify(a: MyGame_Example_ArrayStruct?) {
71+
72+
func testNativeStruct(a: MyGame_Example_ArrayStruct?) {
7173
let a = a!
7274
XCTAssertEqual(a.a, 12.34)
7375
XCTAssertEqual(a.b.count, 15)
@@ -93,8 +95,8 @@ final class FlatBuffersArraysTests: XCTestCase {
9395
XCTAssertEqual(a.e, 1)
9496
XCTAssertEqual(a.f.count, 2)
9597
}
96-
97-
func mutate(table: MyGame_Example_ArrayTable) {
98+
99+
func testMutations(in table: MyGame_Example_ArrayTable) {
98100
let a = table.mutableA!
99101
XCTAssertEqual(a.a, 12.34)
100102
XCTAssertEqual(a.b.count, 15)
@@ -106,7 +108,7 @@ final class FlatBuffersArraysTests: XCTestCase {
106108
XCTAssertEqual(a.c, -127)
107109
XCTAssertEqual(a.d.count, 2)
108110
let nestedStruct1 = a.d[0]
109-
111+
110112
XCTAssertEqual(nestedStruct1.a.reduce(0) { $0 + $1 }, 1)
111113
XCTAssertEqual(nestedStruct1.b, .a)
112114
XCTAssertEqual(nestedStruct1.c[0], .c)
@@ -119,6 +121,37 @@ final class FlatBuffersArraysTests: XCTestCase {
119121
XCTAssertEqual(nestedStruct2.c[1], .a)
120122
XCTAssertEqual(nestedStruct2.d[0], -0x1122334455667788)
121123
XCTAssertEqual(nestedStruct2.d[1], 0x1122334455667788)
124+
125+
XCTAssertTrue(a.mutate(b: 1000, at: 0))
126+
XCTAssertTrue(a.mutate(b: 2000, at: 1))
127+
128+
XCTAssertTrue(nestedStruct2.mutate(c: .a, at: 0))
129+
XCTAssertTrue(nestedStruct2.mutate(c: .b, at: 1))
130+
131+
XCTAssertEqual(nestedStruct2.c[0], .a)
132+
XCTAssertEqual(nestedStruct2.c[1], .b)
133+
134+
XCTAssertTrue(nestedStruct2.mutate(d: 0, at: 0))
135+
XCTAssertTrue(nestedStruct2.mutate(d: 0, at: 1))
136+
137+
XCTAssertEqual(nestedStruct2.d.reduce(0) { $0 + $1 }, 0)
138+
139+
let nativeStruct = table.a?.d[1]
140+
141+
XCTAssertEqual(nativeStruct?.c[0], .a)
142+
XCTAssertEqual(nativeStruct?.c[1], .b)
143+
144+
XCTAssertEqual(nativeStruct?.d[0], 0)
145+
XCTAssertEqual(nativeStruct?.d[1], 0)
146+
147+
XCTAssertTrue(a.mutate(b: 1, at: 0))
148+
XCTAssertTrue(a.mutate(b: 2, at: 1))
149+
150+
XCTAssertTrue(nestedStruct2.mutate(c: .b, at: 0))
151+
XCTAssertTrue(nestedStruct2.mutate(c: .a, at: 1))
152+
153+
XCTAssertTrue(nestedStruct2.mutate(d: -0x1122334455667788, at: 0))
154+
XCTAssertTrue(nestedStruct2.mutate(d: 0x1122334455667788, at: 1))
122155
}
123156
}
124157

@@ -132,3 +165,6 @@ extension InlineArray {
132165
return result
133166
}
134167
}
168+
169+
#endif
170+

tests/swift/Tests/Flatbuffers/arrays_test_generated.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,13 @@ public struct MyGame_Example_NestedStruct_Mutable: FlatBufferStruct, Flatbuffers
121121
public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }
122122

123123
public var a: FlatbufferVector<Int32> { return _accessor.vector(at: 0, count: 2, size: 4) }
124+
@discardableResult public func mutate(a: Int32, at index: Int32) -> Bool { return _accessor.mutate(a, index: 0 + (index * 4)) }
124125
public var b: MyGame_Example_TestEnum { return MyGame_Example_TestEnum(rawValue: _accessor.readBuffer(of: Int8.self, at: 8)) ?? .a }
125126
@discardableResult public func mutate(b: MyGame_Example_TestEnum) -> Bool { return _accessor.mutate(b.rawValue, index: 8) }
126127
public var c: FlatbufferVector<MyGame_Example_TestEnum> { return _accessor.vector(at: 9, count: 2, size: 1) }
128+
@discardableResult public func mutate(c: MyGame_Example_TestEnum, at index: Int32) -> Bool { return _accessor.mutate(c.rawValue, index: 9 + (index * 1)) }
127129
public var d: FlatbufferVector<Int64> { return _accessor.vector(at: 16, count: 2, size: 8) }
130+
@discardableResult public func mutate(d: Int64, at index: Int32) -> Bool { return _accessor.mutate(d, index: 16 + (index * 8)) }
128131

129132
public func unpack() -> MyGame_Example_NestedStruct {
130133
return MyGame_Example_NestedStruct(self)
@@ -250,12 +253,14 @@ public struct MyGame_Example_ArrayStruct_Mutable: FlatBufferStruct, FlatbuffersV
250253
public var a: Float32 { return _accessor.readBuffer(of: Float32.self, at: 0) }
251254
@discardableResult public func mutate(a: Float32) -> Bool { return _accessor.mutate(a, index: 0) }
252255
public var b: FlatbufferVector<Int32> { return _accessor.vector(at: 4, count: 15, size: 4) }
256+
@discardableResult public func mutate(b: Int32, at index: Int32) -> Bool { return _accessor.mutate(b, index: 4 + (index * 4)) }
253257
public var c: Int8 { return _accessor.readBuffer(of: Int8.self, at: 64) }
254258
@discardableResult public func mutate(c: Int8) -> Bool { return _accessor.mutate(c, index: 64) }
255259
public var d: FlatbufferVector<MyGame_Example_NestedStruct_Mutable> { return _accessor.vector(at: 72, count: 2, size: 32) }
256260
public var e: Int32 { return _accessor.readBuffer(of: Int32.self, at: 136) }
257261
@discardableResult public func mutate(e: Int32) -> Bool { return _accessor.mutate(e, index: 136) }
258262
public var f: FlatbufferVector<Int64> { return _accessor.vector(at: 144, count: 2, size: 8) }
263+
@discardableResult public func mutate(f: Int64, at index: Int32) -> Bool { return _accessor.mutate(f, index: 144 + (index * 8)) }
259264

260265
public func unpack() -> MyGame_Example_ArrayStruct {
261266
return MyGame_Example_ArrayStruct(self)

0 commit comments

Comments
 (0)