From 4133a39df80546ff5269894a3961c7069fcd45d0 Mon Sep 17 00:00:00 2001 From: Casper Date: Mon, 29 Mar 2021 19:56:45 -0400 Subject: [PATCH] Rust structz (#6539) * Rust structz * struct of structs test * swift tmp variables Co-authored-by: Casper Neo --- samples/monster_generated.rs | 7 +- src/idl_gen_rust.cpp | 12 +- src/idl_gen_swift.cpp | 4 +- .../monster_test_generated.swift | 64 +- tests/MyGame/Example/StructOfStructs.cs | 83 ++ tests/MyGame/Example/StructOfStructs.go | 80 ++ tests/MyGame/Example/StructOfStructs.java | 44 + tests/MyGame/Example/StructOfStructs.kt | 42 + tests/MyGame/Example/StructOfStructs.lua | 45 + tests/MyGame/Example/StructOfStructs.php | 74 ++ tests/MyGame/Example/StructOfStructs.py | 90 ++ .../generated_cpp17/monster_test_generated.h | 89 ++ .../sub/include_test2_generated.rs | 7 +- tests/monster_test.bfbs | Bin 12704 -> 12944 bytes tests/monster_test.fbs | 6 + tests/monster_test.schema.json | 15 + tests/monster_test_bfbs_generated.h | 1114 +++++++++-------- tests/monster_test_generated.h | 81 ++ tests/monster_test_generated.lobster | 24 + tests/monster_test_generated.rs | 154 ++- ...onster_test_my_game.example_generated.dart | 79 ++ tests/my-game/example/struct-of-structs.ts | 84 ++ .../namespace_test1_generated.rs | 7 +- .../namespace_test2_generated.rs | 7 +- .../rust_usage_test/tests/integration_test.rs | 33 + 25 files changed, 1681 insertions(+), 564 deletions(-) create mode 100644 tests/MyGame/Example/StructOfStructs.cs create mode 100644 tests/MyGame/Example/StructOfStructs.go create mode 100644 tests/MyGame/Example/StructOfStructs.java create mode 100644 tests/MyGame/Example/StructOfStructs.kt create mode 100644 tests/MyGame/Example/StructOfStructs.lua create mode 100644 tests/MyGame/Example/StructOfStructs.php create mode 100644 tests/MyGame/Example/StructOfStructs.py create mode 100644 tests/my-game/example/struct-of-structs.ts diff --git a/samples/monster_generated.rs b/samples/monster_generated.rs index aae5c6c2f..fa9babdb5 100644 --- a/samples/monster_generated.rs +++ b/samples/monster_generated.rs @@ -247,8 +247,13 @@ impl EquipmentT { } // struct Vec3, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] +#[derive(Clone, Copy, PartialEq)] pub struct Vec3(pub [u8; 12]); +impl Default for Vec3 { + fn default() -> Self { + Self([0; 12]) + } +} impl std::fmt::Debug for Vec3 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Vec3") diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index dc26fa32a..248e68c5b 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -2318,7 +2318,10 @@ class RustGenerator : public BaseGenerator { code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field)); code_.SetValue("REF", IsStruct(field.value.type) ? "&" : ""); cb(field); - offset_to_field += SizeOf(field.value.type.base_type) + field.padding; + const size_t size = IsStruct(field.value.type) + ? field.value.type.struct_def->bytesize + : SizeOf(field.value.type.base_type); + offset_to_field += size + field.padding; } } // Generate an accessor struct with constructor for a flatbuffers struct. @@ -2339,8 +2342,13 @@ class RustGenerator : public BaseGenerator { // hold for PartialOrd/Ord. code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}"; code_ += "#[repr(transparent)]"; - code_ += "#[derive(Clone, Copy, PartialEq, Default)]"; + code_ += "#[derive(Clone, Copy, PartialEq)]"; code_ += "pub struct {{STRUCT_NAME}}(pub [u8; {{STRUCT_SIZE}}]);"; + code_ += "impl Default for {{STRUCT_NAME}} { "; + code_ += " fn default() -> Self { "; + code_ += " Self([0; {{STRUCT_SIZE}}])"; + code_ += " }"; + code_ += "}"; // Debug for structs. code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {"; diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp index 984b6aa52..afac8451f 100644 --- a/src/idl_gen_swift.cpp +++ b/src/idl_gen_swift.cpp @@ -935,8 +935,8 @@ class SwiftGenerator : public BaseGenerator { auto type = GenType(field.value.type); code_.SetValue("VALUENAME", name); if (IsStruct(field.value.type)) { - code_ += "var _v = _t.{{VALUENAME}}"; - code_ += "_{{VALUENAME}} = _v.unpack()"; + code_ += "var _v{{VALUENAME}} = _t.{{VALUENAME}}"; + code_ += "_{{VALUENAME}} = _v{{VALUENAME}}.unpack()"; continue; } std::string is_enum = IsEnum(field.value.type) ? ".value" : ""; diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift index fff3ce07f..0eb129f4d 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift @@ -235,8 +235,8 @@ public struct MyGame_Example_Vec3: NativeStruct, NativeObject { _z = _t.z _test1 = _t.test1 _test2 = _t.test2.value - var _v = _t.test3 - _test3 = _v.unpack() + var _vtest3 = _t.test3 + _test3 = _vtest3.unpack() } public var x: Float32 { _x } @@ -334,6 +334,66 @@ public struct MyGame_Example_Ability_Mutable: FlatBufferObject { } } +public struct MyGame_Example_StructOfStructs: NativeStruct, NativeObject { + + static func validateVersion() { FlatBuffersVersion_1_12_0() } + + private var _a: MyGame_Example_Ability + private var _b: MyGame_Example_Test + private var _c: MyGame_Example_Ability + + public init(a: MyGame_Example_Ability, b: MyGame_Example_Test, c: MyGame_Example_Ability) { + _a = a + _b = b + _c = c + } + + public init() { + _a = MyGame_Example_Ability() + _b = MyGame_Example_Test() + _c = MyGame_Example_Ability() + } + + public init(_ _t: inout MyGame_Example_StructOfStructs_Mutable) { + var _va = _t.a + _a = _va.unpack() + var _vb = _t.b + _b = _vb.unpack() + var _vc = _t.c + _c = _vc.unpack() + } + + public var a: MyGame_Example_Ability { _a } + public var b: MyGame_Example_Test { _b } + public var c: MyGame_Example_Ability { _c } +} + +public struct MyGame_Example_StructOfStructs_Mutable: FlatBufferObject { + + static func validateVersion() { FlatBuffersVersion_1_12_0() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Struct + + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) } + + public var a: MyGame_Example_Ability_Mutable { return MyGame_Example_Ability_Mutable(_accessor.bb, o: _accessor.postion + 0) } + public var b: MyGame_Example_Test_Mutable { return MyGame_Example_Test_Mutable(_accessor.bb, o: _accessor.postion + 8) } + public var c: MyGame_Example_Ability_Mutable { return MyGame_Example_Ability_Mutable(_accessor.bb, o: _accessor.postion + 12) } + + + public mutating func unpack() -> MyGame_Example_StructOfStructs { + return MyGame_Example_StructOfStructs(&self) + } + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Example_StructOfStructs?) -> Offset { + guard var obj = obj else { return Offset() } + return pack(&builder, obj: &obj) + } + + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Example_StructOfStructs) -> Offset { + return builder.create(struct: obj) + } +} + public struct MyGame_InParentNamespace: FlatBufferObject, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_1_12_0() } diff --git a/tests/MyGame/Example/StructOfStructs.cs b/tests/MyGame/Example/StructOfStructs.cs new file mode 100644 index 000000000..cdd82fbd4 --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.cs @@ -0,0 +1,83 @@ +// +// automatically generated by the FlatBuffers compiler, do not modify +// + +namespace MyGame.Example +{ + +using global::System; +using global::System.Collections.Generic; +using global::FlatBuffers; + +public struct StructOfStructs : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public StructOfStructs __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public MyGame.Example.Ability A { get { return (new MyGame.Example.Ability()).__assign(__p.bb_pos + 0, __p.bb); } } + public MyGame.Example.Test B { get { return (new MyGame.Example.Test()).__assign(__p.bb_pos + 8, __p.bb); } } + public MyGame.Example.Ability C { get { return (new MyGame.Example.Ability()).__assign(__p.bb_pos + 12, __p.bb); } } + + public static Offset CreateStructOfStructs(FlatBufferBuilder builder, uint a_Id, uint a_Distance, short b_A, sbyte b_B, uint c_Id, uint c_Distance) { + builder.Prep(4, 20); + builder.Prep(4, 8); + builder.PutUint(c_Distance); + builder.PutUint(c_Id); + builder.Prep(2, 4); + builder.Pad(1); + builder.PutSbyte(b_B); + builder.PutShort(b_A); + builder.Prep(4, 8); + builder.PutUint(a_Distance); + builder.PutUint(a_Id); + return new Offset(builder.Offset); + } + public StructOfStructsT UnPack() { + var _o = new StructOfStructsT(); + this.UnPackTo(_o); + return _o; + } + public void UnPackTo(StructOfStructsT _o) { + _o.A = this.A.UnPack(); + _o.B = this.B.UnPack(); + _o.C = this.C.UnPack(); + } + public static Offset Pack(FlatBufferBuilder builder, StructOfStructsT _o) { + if (_o == null) return default(Offset); + var _a_id = _o.A.Id; + var _a_distance = _o.A.Distance; + var _b_a = _o.B.A; + var _b_b = _o.B.B; + var _c_id = _o.C.Id; + var _c_distance = _o.C.Distance; + return CreateStructOfStructs( + builder, + _a_id, + _a_distance, + _b_a, + _b_b, + _c_id, + _c_distance); + } +}; + +public class StructOfStructsT +{ + [Newtonsoft.Json.JsonProperty("a")] + public MyGame.Example.AbilityT A { get; set; } + [Newtonsoft.Json.JsonProperty("b")] + public MyGame.Example.TestT B { get; set; } + [Newtonsoft.Json.JsonProperty("c")] + public MyGame.Example.AbilityT C { get; set; } + + public StructOfStructsT() { + this.A = new MyGame.Example.AbilityT(); + this.B = new MyGame.Example.TestT(); + this.C = new MyGame.Example.AbilityT(); + } +} + + +} diff --git a/tests/MyGame/Example/StructOfStructs.go b/tests/MyGame/Example/StructOfStructs.go new file mode 100644 index 000000000..35ccfcb41 --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.go @@ -0,0 +1,80 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package Example + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type StructOfStructsT struct { + A *AbilityT + B *TestT + C *AbilityT +} + +func (t *StructOfStructsT) Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + if t == nil { return 0 } + return CreateStructOfStructs(builder, t.A.Id, t.A.Distance, t.B.A, t.B.B, t.C.Id, t.C.Distance) +} +func (rcv *StructOfStructs) UnPackTo(t *StructOfStructsT) { + t.A = rcv.A(nil).UnPack() + t.B = rcv.B(nil).UnPack() + t.C = rcv.C(nil).UnPack() +} + +func (rcv *StructOfStructs) UnPack() *StructOfStructsT { + if rcv == nil { return nil } + t := &StructOfStructsT{} + rcv.UnPackTo(t) + return t +} + +type StructOfStructs struct { + _tab flatbuffers.Struct +} + +func (rcv *StructOfStructs) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *StructOfStructs) Table() flatbuffers.Table { + return rcv._tab.Table +} + +func (rcv *StructOfStructs) A(obj *Ability) *Ability { + if obj == nil { + obj = new(Ability) + } + obj.Init(rcv._tab.Bytes, rcv._tab.Pos+0) + return obj +} +func (rcv *StructOfStructs) B(obj *Test) *Test { + if obj == nil { + obj = new(Test) + } + obj.Init(rcv._tab.Bytes, rcv._tab.Pos+8) + return obj +} +func (rcv *StructOfStructs) C(obj *Ability) *Ability { + if obj == nil { + obj = new(Ability) + } + obj.Init(rcv._tab.Bytes, rcv._tab.Pos+12) + return obj +} + +func CreateStructOfStructs(builder *flatbuffers.Builder, a_id uint32, a_distance uint32, b_a int16, b_b int8, c_id uint32, c_distance uint32) flatbuffers.UOffsetT { + builder.Prep(4, 20) + builder.Prep(4, 8) + builder.PrependUint32(c_distance) + builder.PrependUint32(c_id) + builder.Prep(2, 4) + builder.Pad(1) + builder.PrependInt8(b_b) + builder.PrependInt16(b_a) + builder.Prep(4, 8) + builder.PrependUint32(a_distance) + builder.PrependUint32(a_id) + return builder.Offset() +} diff --git a/tests/MyGame/Example/StructOfStructs.java b/tests/MyGame/Example/StructOfStructs.java new file mode 100644 index 000000000..ea1ec133e --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.java @@ -0,0 +1,44 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example; + +import java.nio.*; +import java.lang.*; +import java.util.*; +import com.google.flatbuffers.*; + +@SuppressWarnings("unused") +public final class StructOfStructs extends Struct { + public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } + public StructOfStructs __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public MyGame.Example.Ability a() { return a(new MyGame.Example.Ability()); } + public MyGame.Example.Ability a(MyGame.Example.Ability obj) { return obj.__assign(bb_pos + 0, bb); } + public MyGame.Example.Test b() { return b(new MyGame.Example.Test()); } + public MyGame.Example.Test b(MyGame.Example.Test obj) { return obj.__assign(bb_pos + 8, bb); } + public MyGame.Example.Ability c() { return c(new MyGame.Example.Ability()); } + public MyGame.Example.Ability c(MyGame.Example.Ability obj) { return obj.__assign(bb_pos + 12, bb); } + + public static int createStructOfStructs(FlatBufferBuilder builder, long a_id, long a_distance, short b_a, byte b_b, long c_id, long c_distance) { + builder.prep(4, 20); + builder.prep(4, 8); + builder.putInt((int)c_distance); + builder.putInt((int)c_id); + builder.prep(2, 4); + builder.pad(1); + builder.putByte(b_b); + builder.putShort(b_a); + builder.prep(4, 8); + builder.putInt((int)a_distance); + builder.putInt((int)a_id); + return builder.offset(); + } + + public static final class Vector extends BaseVector { + public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; } + + public StructOfStructs get(int j) { return get(new StructOfStructs(), j); } + public StructOfStructs get(StructOfStructs obj, int j) { return obj.__assign(__element(j), bb); } + } +} + diff --git a/tests/MyGame/Example/StructOfStructs.kt b/tests/MyGame/Example/StructOfStructs.kt new file mode 100644 index 000000000..2a6bf9b7c --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.kt @@ -0,0 +1,42 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class StructOfStructs : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : StructOfStructs { + __init(_i, _bb) + return this + } + val a : MyGame.Example.Ability? get() = a(MyGame.Example.Ability()) + fun a(obj: MyGame.Example.Ability) : MyGame.Example.Ability? = obj.__assign(bb_pos + 0, bb) + val b : MyGame.Example.Test? get() = b(MyGame.Example.Test()) + fun b(obj: MyGame.Example.Test) : MyGame.Example.Test? = obj.__assign(bb_pos + 8, bb) + val c : MyGame.Example.Ability? get() = c(MyGame.Example.Ability()) + fun c(obj: MyGame.Example.Ability) : MyGame.Example.Ability? = obj.__assign(bb_pos + 12, bb) + companion object { + fun createStructOfStructs(builder: FlatBufferBuilder, a_id: UInt, a_distance: UInt, b_a: Short, b_b: Byte, c_id: UInt, c_distance: UInt) : Int { + builder.prep(4, 20) + builder.prep(4, 8) + builder.putInt(c_distance.toInt()) + builder.putInt(c_id.toInt()) + builder.prep(2, 4) + builder.pad(1) + builder.putByte(b_b) + builder.putShort(b_a) + builder.prep(4, 8) + builder.putInt(a_distance.toInt()) + builder.putInt(a_id.toInt()) + return builder.offset() + } + } +} diff --git a/tests/MyGame/Example/StructOfStructs.lua b/tests/MyGame/Example/StructOfStructs.lua new file mode 100644 index 000000000..827e94214 --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.lua @@ -0,0 +1,45 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local StructOfStructs = {} -- the module +local StructOfStructs_mt = {} -- the class metatable + +function StructOfStructs.New() + local o = {} + setmetatable(o, {__index = StructOfStructs_mt}) + return o +end +function StructOfStructs_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function StructOfStructs_mt:A(obj) + obj:Init(self.view.bytes, self.view.pos + 0) + return obj +end +function StructOfStructs_mt:B(obj) + obj:Init(self.view.bytes, self.view.pos + 8) + return obj +end +function StructOfStructs_mt:C(obj) + obj:Init(self.view.bytes, self.view.pos + 12) + return obj +end +function StructOfStructs.CreateStructOfStructs(builder, a_id, a_distance, b_a, b_b, c_id, c_distance) + builder:Prep(4, 20) + builder:Prep(4, 8) + builder:PrependUint32(c_distance) + builder:PrependUint32(c_id) + builder:Prep(2, 4) + builder:Pad(1) + builder:PrependInt8(b_b) + builder:PrependInt16(b_a) + builder:Prep(4, 8) + builder:PrependUint32(a_distance) + builder:PrependUint32(a_id) + return builder:Offset() +end + +return StructOfStructs -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/StructOfStructs.php b/tests/MyGame/Example/StructOfStructs.php new file mode 100644 index 000000000..fe5fac3ad --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.php @@ -0,0 +1,74 @@ +bb_pos = $_i; + $this->bb = $_bb; + return $this; + } + + /** + * @return Ability + */ + public function getA() + { + $obj = new Ability(); + $obj->init($this->bb_pos + 0, $this->bb); + return $obj; + } + + /** + * @return Test + */ + public function getB() + { + $obj = new Test(); + $obj->init($this->bb_pos + 8, $this->bb); + return $obj; + } + + /** + * @return Ability + */ + public function getC() + { + $obj = new Ability(); + $obj->init($this->bb_pos + 12, $this->bb); + return $obj; + } + + + /** + * @return int offset + */ + public static function createStructOfStructs(FlatBufferBuilder $builder, $a_id, $a_distance, $b_a, $b_b, $c_id, $c_distance) + { + $builder->prep(4, 20); + $builder->prep(4, 8); + $builder->putUint($c_distance); + $builder->putUint($c_id); + $builder->prep(2, 4); + $builder->pad(1); + $builder->putSbyte($b_b); + $builder->putShort($b_a); + $builder->prep(4, 8); + $builder->putUint($a_distance); + $builder->putUint($a_id); + return $builder->offset(); + } +} diff --git a/tests/MyGame/Example/StructOfStructs.py b/tests/MyGame/Example/StructOfStructs.py new file mode 100644 index 000000000..0dcf3d558 --- /dev/null +++ b/tests/MyGame/Example/StructOfStructs.py @@ -0,0 +1,90 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: Example + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class StructOfStructs(object): + __slots__ = ['_tab'] + + @classmethod + def SizeOf(cls): + return 20 + + # StructOfStructs + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # StructOfStructs + def A(self, obj): + obj.Init(self._tab.Bytes, self._tab.Pos + 0) + return obj + + # StructOfStructs + def B(self, obj): + obj.Init(self._tab.Bytes, self._tab.Pos + 8) + return obj + + # StructOfStructs + def C(self, obj): + obj.Init(self._tab.Bytes, self._tab.Pos + 12) + return obj + + +def CreateStructOfStructs(builder, a_id, a_distance, b_a, b_b, c_id, c_distance): + builder.Prep(4, 20) + builder.Prep(4, 8) + builder.PrependUint32(c_distance) + builder.PrependUint32(c_id) + builder.Prep(2, 4) + builder.Pad(1) + builder.PrependInt8(b_b) + builder.PrependInt16(b_a) + builder.Prep(4, 8) + builder.PrependUint32(a_distance) + builder.PrependUint32(a_id) + return builder.Offset() + +import MyGame.Example.Ability +import MyGame.Example.Test +try: + from typing import Optional +except: + pass + +class StructOfStructsT(object): + + # StructOfStructsT + def __init__(self): + self.a = None # type: Optional[MyGame.Example.Ability.AbilityT] + self.b = None # type: Optional[MyGame.Example.Test.TestT] + self.c = None # type: Optional[MyGame.Example.Ability.AbilityT] + + @classmethod + def InitFromBuf(cls, buf, pos): + structOfStructs = StructOfStructs() + structOfStructs.Init(buf, pos) + return cls.InitFromObj(structOfStructs) + + @classmethod + def InitFromObj(cls, structOfStructs): + x = StructOfStructsT() + x._UnPack(structOfStructs) + return x + + # StructOfStructsT + def _UnPack(self, structOfStructs): + if structOfStructs is None: + return + if structOfStructs.A(MyGame.Example.Ability.Ability()) is not None: + self.a = MyGame.Example.Ability.AbilityT.InitFromObj(structOfStructs.A(MyGame.Example.Ability.Ability())) + if structOfStructs.B(MyGame.Example.Test.Test()) is not None: + self.b = MyGame.Example.Test.TestT.InitFromObj(structOfStructs.B(MyGame.Example.Test.Test())) + if structOfStructs.C(MyGame.Example.Ability.Ability()) is not None: + self.c = MyGame.Example.Ability.AbilityT.InitFromObj(structOfStructs.C(MyGame.Example.Ability.Ability())) + + # StructOfStructsT + def Pack(self, builder): + return CreateStructOfStructs(builder, self.a.id, self.a.distance, self.b.a, self.b.b, self.c.id, self.c.distance) diff --git a/tests/cpp17/generated_cpp17/monster_test_generated.h b/tests/cpp17/generated_cpp17/monster_test_generated.h index 30aee2272..6f69ae9b6 100644 --- a/tests/cpp17/generated_cpp17/monster_test_generated.h +++ b/tests/cpp17/generated_cpp17/monster_test_generated.h @@ -33,6 +33,8 @@ struct Vec3; struct Ability; +struct StructOfStructs; + struct Stat; struct StatBuilder; struct StatT; @@ -69,6 +71,8 @@ inline const flatbuffers::TypeTable *Vec3TypeTable(); inline const flatbuffers::TypeTable *AbilityTypeTable(); +inline const flatbuffers::TypeTable *StructOfStructsTypeTable(); + inline const flatbuffers::TypeTable *StatTypeTable(); inline const flatbuffers::TypeTable *ReferrableTypeTable(); @@ -693,6 +697,69 @@ struct Ability::Traits { static constexpr size_t fields_number = 2; }; +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) StructOfStructs FLATBUFFERS_FINAL_CLASS { + private: + MyGame::Example::Ability a_; + MyGame::Example::Test b_; + MyGame::Example::Ability c_; + + public: + struct Traits; + static const flatbuffers::TypeTable *MiniReflectTypeTable() { + return StructOfStructsTypeTable(); + } + StructOfStructs() + : a_(), + b_(), + c_() { + } + StructOfStructs(const MyGame::Example::Ability &_a, const MyGame::Example::Test &_b, const MyGame::Example::Ability &_c) + : a_(_a), + b_(_b), + c_(_c) { + } + const MyGame::Example::Ability &a() const { + return a_; + } + MyGame::Example::Ability &mutable_a() { + return a_; + } + const MyGame::Example::Test &b() const { + return b_; + } + MyGame::Example::Test &mutable_b() { + return b_; + } + const MyGame::Example::Ability &c() const { + return c_; + } + MyGame::Example::Ability &mutable_c() { + return c_; + } + template + auto get_field() const { + if constexpr (Index == 0) return a(); + else if constexpr (Index == 1) return b(); + else if constexpr (Index == 2) return c(); + else static_assert(Index != Index, "Invalid Field Index"); + } +}; +FLATBUFFERS_STRUCT_END(StructOfStructs, 20); + +struct StructOfStructs::Traits { + using type = StructOfStructs; + static constexpr auto name = "StructOfStructs"; + static constexpr auto fully_qualified_name = "MyGame.Example.StructOfStructs"; + static constexpr std::array field_names = { + "a", + "b", + "c" + }; + template + using FieldType = decltype(std::declval().get_field()); + static constexpr size_t fields_number = 3; +}; + } // namespace Example struct InParentNamespaceT : public flatbuffers::NativeTable { @@ -3384,6 +3451,28 @@ inline const flatbuffers::TypeTable *AbilityTypeTable() { return &tt; } +inline const flatbuffers::TypeTable *StructOfStructsTypeTable() { + static const flatbuffers::TypeCode type_codes[] = { + { flatbuffers::ET_SEQUENCE, 0, 0 }, + { flatbuffers::ET_SEQUENCE, 0, 1 }, + { flatbuffers::ET_SEQUENCE, 0, 0 } + }; + static const flatbuffers::TypeFunction type_refs[] = { + MyGame::Example::AbilityTypeTable, + MyGame::Example::TestTypeTable + }; + static const int64_t values[] = { 0, 8, 12, 20 }; + static const char * const names[] = { + "a", + "b", + "c" + }; + static const flatbuffers::TypeTable tt = { + flatbuffers::ST_STRUCT, 3, type_codes, type_refs, nullptr, values, names + }; + return &tt; +} + inline const flatbuffers::TypeTable *StatTypeTable() { static const flatbuffers::TypeCode type_codes[] = { { flatbuffers::ET_STRING, 0, -1 }, diff --git a/tests/include_test/sub/include_test2_generated.rs b/tests/include_test/sub/include_test2_generated.rs index 787ec19f1..709d488d3 100644 --- a/tests/include_test/sub/include_test2_generated.rs +++ b/tests/include_test/sub/include_test2_generated.rs @@ -110,8 +110,13 @@ impl<'a> flatbuffers::Verifiable for FromInclude { impl flatbuffers::SimpleToVerifyInSlice for FromInclude {} // struct Unused, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] +#[derive(Clone, Copy, PartialEq)] pub struct Unused(pub [u8; 4]); +impl Default for Unused { + fn default() -> Self { + Self([0; 4]) + } +} impl std::fmt::Debug for Unused { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Unused") diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs index ad26b97007d5a362b033423870dd1b0957d58fe0..12e0150cf97496beb5160b97149cf38c4469b980 100644 GIT binary patch delta 2514 zcmZve4@}hO8OPuEIqu+&1MUtuj^DuvCvb4k6OmAB&8=lCl5=GpWt(A!7Eq!WL`#wM z-?TH`l9`3zzD?7bmbAuXUB?zv&0@@Am@y_@Hlt`ZwQ^EK1VjW;MB;jTe!pLp^XxBq z^WOWupZEJb@AJHW?$g%Z&DIs*qi!M0kMOJJ|# zIp;;q_e4#PxxLI8gyjh?sB`O0n&8SR@g;*KlAZwDbkL{?GIxnNDNIjrJr_aNYWtv$ z8`KPLT`hzYKeN7_UG5g5D_e+9x$akZYZ`^<lk2gRKSJ0AL zBSZL8>I(YT6K#U3nnKe#duF_*(>fY{A?k@yMzr#DO8(FFeH~aUvB<#E(YMmtI8eBk0NU(}yEC z?eNpd5iC0Vcwm2(Ub>1Vha%hYQ@fAezp7CKS5-<*;jF!sz8pqTdZVXnG|mQ}S}kbo zXz!?MLmtIvj#3&O#qIQfdVn*K`}wuUXRUf>Y1T=6lJ29aYnn;dnCcNlMo^y_!jTL+ z{*swY{bM+mx!+TJJx=B6C6!Irwe|h}x+Zh2&H{dm=kKP^EhWp1g zE1lOcmK8#6mL1Q#eo4I(=yNIN=`sD_TJR6oI(jexOLhyrI*E?#CK{N;>1?kwVmA9( z%DaJpqR`qK2q{hU@eO>Tgk=&k-LH7IOg-*tMU1DO3H-s`NW)W@b}RG&>*qAl#+wM| zDAIx7a0gqN{n zap20BybsLa^fIq`*Gkro)<7MrE^Dlc&g9{CnAQX~LU%>pVwhA2+x%CZ1c5L)1p(d<69rGJTfNXtopT5l z)_dNYUy@RvN_O~BbVug!*Fr^x@m1jpnwrOAp+ccMa27SvrhDit+C$^_Fkj@AR%H9! zRJ?#HpO?n&pwZVzpD!R%qEwz-cwC?N#v}c=?rI@TQ7@B@=53p~5(lEuC~}IQlJ^lR zcBkotQO)<39sD>w@a1Ky*W-`5<2f$s{jAP3s$sl-`UZ{^@+vrzp}e^R(pH8o7=^v`$#Qy?(WmOQy!XGb6=B`{MSQ!pw(!o z54BpWpXzfzmyKLh#>3^sH`j5z0x!JLylqGO=D^EcojY5*e$uAbuM08!KV6gf2~+YCLp(!wQ&T};wsxe@c(M4~pIyJWmh kkmIDf^2l(rI9ySBOiJV7n`N&UWHMeX|D#O7-SR*GA4IpJc>n+a delta 2346 zcmZveYfKbZ6vxj!`(SrnV3*}NzyQl*SHKlesqsM#ZB~MoT54KD>Z*tYiK0Oy^bxJ5 z@q@9AdW2jd5m8e=R`qJUOyRS@ujh=7QIhV7YI5m>s(?46nWn{)o> zG55~FO?4X$kpPhE&i(X|IVsR-2GH`g;G^cy(&&OKe6{3i zAzJANkt@pRx`@Mztu!c7u(y?R9O0CK^RdlACj-NARU7TX0(@|tnz0-UT4<3b8~3$P zr6vo{wa^JoAqKV5m?j@rrIDG{eSCA7@Z)u&;dPw5-}+)3}cdQ0*~S z$(#mEGq{vHYK$xNs=>@`sAUkrFas>`fjZS7a~GHspr652-yxGZ*Lu!}Ym`RVybxfV z)|$VL%8TaCi~=~zW1|F+rvo_19UV^t=2kp*pDqPfqPd+G1-WoZJCz5yMFag2G*>>; z?)6&Olu{bSi8}f-B8^7E*U-X9Yv7awE_^Q~~`(d9S zGNld1==+$(c)X9AVu}%-lPgxjnCD9H#(PiIAWT*g@isaTn~n#b(>b26SLd<3m&RiY zFutD(WC@q_Q@NaiCH-`mhXege#*Bq5j`Lu!k~P70I4&JwfLw9xVL*lNJ)_DvHy#+E zb8(WWr?v5kSlUNpac((uaJuHqDMif~Bu~6u^wFO9<#>FMn&KsKmbNA&V)b(}CAj6J z7k&><$;q-8RFPm8<8&zD1G(NGoRS$&KMf}2$l4)4TT{whJU|6@HxlcTX{h}_AAxaAeqCQGqR z?2Qwq?2^En9aL@FQMIn>%k7)^yos(S&z0L=P3loF4((mXWW6Lgr3hD!&{rvY@!AND zr`W|1B{-tdGRn?p#6qjcUOVdE&>aY&ZpVby7%vgTB5*t&^IobhCK&f#@n zkuy5fH>*?HvTQs5fyB$$W@nr=kI$FzF|nH+rB4ht`PkTWfxIBR6Ik$ynw^CU46mmn z-1P5|(h*fmFno-s|lId_;( zQu!sRTkzl;h28Dun`~3hD=}=`wzHy&$MY=Y|JL?OAFFOs)f=|JdX5Q%cE%o1>*E3^ s9A_&WmoJI`l&mNjRlX8 Self { + Self([0; 4]) + } +} impl std::fmt::Debug for Test { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Test") @@ -1111,8 +1116,13 @@ impl TestT { // struct Vec3, aligned to 8 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] +#[derive(Clone, Copy, PartialEq)] pub struct Vec3(pub [u8; 32]); +impl Default for Vec3 { + fn default() -> Self { + Self([0; 32]) + } +} impl std::fmt::Debug for Vec3 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Vec3") @@ -1356,8 +1366,13 @@ impl Vec3T { // struct Ability, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] +#[derive(Clone, Copy, PartialEq)] pub struct Ability(pub [u8; 8]); +impl Default for Ability { + fn default() -> Self { + Self([0; 8]) + } +} impl std::fmt::Debug for Ability { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Ability") @@ -1508,6 +1523,139 @@ impl AbilityT { } } +// struct StructOfStructs, aligned to 4 +#[repr(transparent)] +#[derive(Clone, Copy, PartialEq)] +pub struct StructOfStructs(pub [u8; 20]); +impl Default for StructOfStructs { + fn default() -> Self { + Self([0; 20]) + } +} +impl std::fmt::Debug for StructOfStructs { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("StructOfStructs") + .field("a", &self.a()) + .field("b", &self.b()) + .field("c", &self.c()) + .finish() + } +} + +impl flatbuffers::SimpleToVerifyInSlice for StructOfStructs {} +impl flatbuffers::SafeSliceAccess for StructOfStructs {} +impl<'a> flatbuffers::Follow<'a> for StructOfStructs { + type Inner = &'a StructOfStructs; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + <&'a StructOfStructs>::follow(buf, loc) + } +} +impl<'a> flatbuffers::Follow<'a> for &'a StructOfStructs { + type Inner = &'a StructOfStructs; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::follow_cast_ref::(buf, loc) + } +} +impl<'b> flatbuffers::Push for StructOfStructs { + type Output = StructOfStructs; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + let src = unsafe { + ::std::slice::from_raw_parts(self as *const StructOfStructs as *const u8, Self::size()) + }; + dst.copy_from_slice(src); + } +} +impl<'b> flatbuffers::Push for &'b StructOfStructs { + type Output = StructOfStructs; + + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + let src = unsafe { + ::std::slice::from_raw_parts(*self as *const StructOfStructs as *const u8, Self::size()) + }; + dst.copy_from_slice(src); + } +} + +impl<'a> flatbuffers::Verifiable for StructOfStructs { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.in_buffer::(pos) + } +} +impl StructOfStructs { + #[allow(clippy::too_many_arguments)] + pub fn new( + a: &Ability, + b: &Test, + c: &Ability, + ) -> Self { + let mut s = Self([0; 20]); + s.set_a(&a); + s.set_b(&b); + s.set_c(&c); + s + } + + pub const fn get_fully_qualified_name() -> &'static str { + "MyGame.Example.StructOfStructs" + } + + pub fn a(&self) -> &Ability { + unsafe { &*(self.0[0..].as_ptr() as *const Ability) } + } + + pub fn set_a(&mut self, x: &Ability) { + self.0[0..0+8].copy_from_slice(&x.0) + } + + pub fn b(&self) -> &Test { + unsafe { &*(self.0[8..].as_ptr() as *const Test) } + } + + pub fn set_b(&mut self, x: &Test) { + self.0[8..8+4].copy_from_slice(&x.0) + } + + pub fn c(&self) -> &Ability { + unsafe { &*(self.0[12..].as_ptr() as *const Ability) } + } + + pub fn set_c(&mut self, x: &Ability) { + self.0[12..12+8].copy_from_slice(&x.0) + } + + pub fn unpack(&self) -> StructOfStructsT { + StructOfStructsT { + a: self.a().unpack(), + b: self.b().unpack(), + c: self.c().unpack(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct StructOfStructsT { + pub a: AbilityT, + pub b: TestT, + pub c: AbilityT, +} +impl StructOfStructsT { + pub fn pack(&self) -> StructOfStructs { + StructOfStructs::new( + &self.a.pack(), + &self.b.pack(), + &self.c.pack(), + ) + } +} + pub enum TestSimpleTableWithEnumOffset {} #[derive(Copy, Clone, PartialEq)] diff --git a/tests/monster_test_my_game.example_generated.dart b/tests/monster_test_my_game.example_generated.dart index 1ff9feea2..4a5f5c999 100644 --- a/tests/monster_test_my_game.example_generated.dart +++ b/tests/monster_test_my_game.example_generated.dart @@ -544,6 +544,85 @@ class AbilityObjectBuilder extends fb.ObjectBuilder { return fbBuilder.finish(offset, fileIdentifier); } } +class StructOfStructs { + StructOfStructs._(this._bc, this._bcOffset); + + static const fb.Reader reader = const _StructOfStructsReader(); + + final fb.BufferContext _bc; + final int _bcOffset; + + Ability get a => Ability.reader.read(_bc, _bcOffset + 0); + Test get b => Test.reader.read(_bc, _bcOffset + 8); + Ability get c => Ability.reader.read(_bc, _bcOffset + 12); + + @override + String toString() { + return 'StructOfStructs{a: $a, b: $b, c: $c}'; + } +} + +class _StructOfStructsReader extends fb.StructReader { + const _StructOfStructsReader(); + + @override + int get size => 20; + + @override + StructOfStructs createObject(fb.BufferContext bc, int offset) => + new StructOfStructs._(bc, offset); +} + +class StructOfStructsBuilder { + StructOfStructsBuilder(this.fbBuilder) { + assert(fbBuilder != null); + } + + final fb.Builder fbBuilder; + + int finish(fb.StructBuilder a, fb.StructBuilder b, fb.StructBuilder c) { + c(); + b(); + a(); + return fbBuilder.offset; + } + +} + +class StructOfStructsObjectBuilder extends fb.ObjectBuilder { + final AbilityObjectBuilder _a; + final TestObjectBuilder _b; + final AbilityObjectBuilder _c; + + StructOfStructsObjectBuilder({ + AbilityObjectBuilder a, + TestObjectBuilder b, + AbilityObjectBuilder c, + }) + : _a = a, + _b = b, + _c = c; + + /// Finish building, and store into the [fbBuilder]. + @override + int finish( + fb.Builder fbBuilder) { + assert(fbBuilder != null); + + _c.finish(fbBuilder); + _b.finish(fbBuilder); + _a.finish(fbBuilder); + return fbBuilder.offset; + } + + /// Convenience method to serialize to byte list. + @override + Uint8List toBytes([String fileIdentifier]) { + fb.Builder fbBuilder = new fb.Builder(); + int offset = finish(fbBuilder); + return fbBuilder.finish(offset, fileIdentifier); + } +} class Stat { Stat._(this._bc, this._bcOffset); factory Stat(List bytes) { diff --git a/tests/my-game/example/struct-of-structs.ts b/tests/my-game/example/struct-of-structs.ts new file mode 100644 index 000000000..3b7d3d492 --- /dev/null +++ b/tests/my-game/example/struct-of-structs.ts @@ -0,0 +1,84 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { Ability, AbilityT } from '../../my-game/example/ability'; +import { Test, TestT } from '../../my-game/example/test'; + + +export class StructOfStructs { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; +__init(i:number, bb:flatbuffers.ByteBuffer):StructOfStructs { + this.bb_pos = i; + this.bb = bb; + return this; +} + +a(obj?:Ability):Ability|null { + return (obj || new Ability()).__init(this.bb_pos, this.bb!); +} + +b(obj?:Test):Test|null { + return (obj || new Test()).__init(this.bb_pos + 8, this.bb!); +} + +c(obj?:Ability):Ability|null { + return (obj || new Ability()).__init(this.bb_pos + 12, this.bb!); +} + +static sizeOf():number { + return 20; +} + +static createStructOfStructs(builder:flatbuffers.Builder, a_id: number, a_distance: number, b_a: number, b_b: number, c_id: number, c_distance: number):flatbuffers.Offset { + builder.prep(4, 20); + builder.prep(4, 8); + builder.writeInt32(c_distance); + builder.writeInt32(c_id); + builder.prep(2, 4); + builder.pad(1); + builder.writeInt8(b_b); + builder.writeInt16(b_a); + builder.prep(4, 8); + builder.writeInt32(a_distance); + builder.writeInt32(a_id); + return builder.offset(); +} + + +unpack(): StructOfStructsT { + return new StructOfStructsT( + (this.a() !== null ? this.a()!.unpack() : null), + (this.b() !== null ? this.b()!.unpack() : null), + (this.c() !== null ? this.c()!.unpack() : null) + ); +} + + +unpackTo(_o: StructOfStructsT): void { + _o.a = (this.a() !== null ? this.a()!.unpack() : null); + _o.b = (this.b() !== null ? this.b()!.unpack() : null); + _o.c = (this.c() !== null ? this.c()!.unpack() : null); +} +} + +export class StructOfStructsT { +constructor( + public a: AbilityT|null = null, + public b: TestT|null = null, + public c: AbilityT|null = null +){} + + +pack(builder:flatbuffers.Builder): flatbuffers.Offset { + return StructOfStructs.createStructOfStructs(builder, + (this.a === null ? 0 : this.a.id!), + (this.a === null ? 0 : this.a.distance!), + (this.b === null ? 0 : this.b.a!), + (this.b === null ? 0 : this.b.b!), + (this.c === null ? 0 : this.c.id!), + (this.c === null ? 0 : this.c.distance!) + ); +} +} diff --git a/tests/namespace_test/namespace_test1_generated.rs b/tests/namespace_test/namespace_test1_generated.rs index 183d904ef..7a8863103 100644 --- a/tests/namespace_test/namespace_test1_generated.rs +++ b/tests/namespace_test/namespace_test1_generated.rs @@ -247,8 +247,13 @@ impl<'a> flatbuffers::Verifiable for EnumInNestedNS { impl flatbuffers::SimpleToVerifyInSlice for EnumInNestedNS {} // struct StructInNestedNS, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] +#[derive(Clone, Copy, PartialEq)] pub struct StructInNestedNS(pub [u8; 8]); +impl Default for StructInNestedNS { + fn default() -> Self { + Self([0; 8]) + } +} impl std::fmt::Debug for StructInNestedNS { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("StructInNestedNS") diff --git a/tests/namespace_test/namespace_test2_generated.rs b/tests/namespace_test/namespace_test2_generated.rs index 815d9f4ae..f21eeeef6 100644 --- a/tests/namespace_test/namespace_test2_generated.rs +++ b/tests/namespace_test/namespace_test2_generated.rs @@ -247,8 +247,13 @@ impl<'a> flatbuffers::Verifiable for EnumInNestedNS { impl flatbuffers::SimpleToVerifyInSlice for EnumInNestedNS {} // struct StructInNestedNS, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] +#[derive(Clone, Copy, PartialEq)] pub struct StructInNestedNS(pub [u8; 8]); +impl Default for StructInNestedNS { + fn default() -> Self { + Self([0; 8]) + } +} impl std::fmt::Debug for StructInNestedNS { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("StructInNestedNS") diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index ccc69d2b1..e606b3b79 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -1111,6 +1111,39 @@ mod roundtrip_byteswap { // fn fuzz_f64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_f64 as fn(f64)); } } +quickcheck! { + fn struct_of_structs( + a_id: u32, + a_distance: u32, + b_a: i16, + b_b: i8, + c_id: u32, + c_distance: u32 + ) -> bool { + use my_game::example::*; + let mut sos = StructOfStructs::default(); + let mut a = Ability::default(); + a.set_id(a_id); + a.set_distance(a_distance); + let mut b = Test::default(); + b.set_a(b_a); + b.set_b(b_b); + let mut c = Ability::default(); + c.set_id(c_id); + c.set_distance(c_distance); + sos.set_a(&a); + sos.set_b(&b); + sos.set_c(&c); + + sos.a().id() == a_id && + sos.a().distance() == a_distance && + sos.b().a() == b_a && + sos.b().b() == b_b && + sos.c().id() == c_id && + sos.c().distance() == c_distance + } +} + #[cfg(not(miri))] // slow. #[cfg(test)] mod roundtrip_vectors {