private void TestType <T>(bool listCache, Func <T> generator) where T : IEquatable <T> { var options = new FlatBufferSerializerOptions(listCache ? FlatBufferDeserializationOption.VectorCache : FlatBufferDeserializationOption.Lazy); FlatBufferSerializer serializer = new FlatBufferSerializer(options); { var memoryTable = new RootTable <IList <T> > { Vector = Enumerable.Range(0, 10).Select(i => generator()).ToArray() }; Span <byte> memory = new byte[10240]; int offset = serializer.Serialize(memoryTable, memory); var memoryTableResult = serializer.Parse <RootTable <IList <T> > >(memory.Slice(0, offset).ToArray()); var resultVector = memoryTableResult.Vector; for (int i = 0; i < memoryTableResult.Vector.Count; ++i) { Assert.AreEqual <T>(memoryTable.Vector[i], resultVector[i]); // reference equality should correspond to the serializer. Assert.AreEqual(listCache, object.ReferenceEquals(resultVector[i], resultVector[i])); } } { var memoryTable = new RootTable <IReadOnlyList <T> > { Vector = Enumerable.Range(0, 10).Select(i => generator()).ToArray() }; Span <byte> memory = new byte[10240]; int offset = serializer.Serialize(memoryTable, memory); var memoryTableResult = serializer.Parse <RootTable <IReadOnlyList <T> > >(memory.Slice(0, offset).ToArray()); var resultVector = memoryTableResult.Vector; for (int i = 0; i < memoryTableResult.Vector.Count; ++i) { Assert.AreEqual(memoryTable.Vector[i], resultVector[i]); // reference equality should correspond to the serializer. Assert.AreEqual(listCache, object.ReferenceEquals(resultVector[i], resultVector[i])); } } { var memoryTable = new RootTable <T[]> { Vector = Enumerable.Range(0, 10).Select(i => generator()).ToArray() }; Span <byte> memory = new byte[10240]; int offset = serializer.Serialize(memoryTable, memory); var memoryTableResult = serializer.Parse <RootTable <T[]> >(memory.Slice(0, offset).ToArray()); var resultVector = memoryTableResult.Vector; for (int i = 0; i < memoryTableResult.Vector.Length; ++i) { Assert.AreEqual(memoryTable.Vector[i], resultVector[i]); } } }
public void TestInitialize() { this.stringDictionary = new TableVector <string> { Vector = new Dictionary <string, VectorMember <string> >() }; this.intDictionary = new TableVector <int> { Vector = new Dictionary <int, VectorMember <int> >() }; for (int i = 0; i < 10; ++i) { this.stringDictionary.Vector[i.ToString()] = new VectorMember <string> { Key = i.ToString(), Value = Guid.NewGuid().ToString() }; this.intDictionary.Vector[i] = new VectorMember <int> { Key = i, Value = Guid.NewGuid().ToString() }; } Span <byte> buffer = new byte[1024]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); int bytesWritten = serializer.Serialize(this.stringDictionary, buffer); this.stringDictionary = serializer.Parse <TableVector <string> >(buffer.Slice(0, bytesWritten).ToArray()); bytesWritten = serializer.Serialize(this.intDictionary, buffer); this.intDictionary = serializer.Parse <TableVector <int> >(buffer.Slice(0, bytesWritten).ToArray()); }
static void Test(FlatBufferDeserializationOption option) { var table = new Table <IList <WriteThroughStruct <long> > > { Struct = new List <WriteThroughStruct <long> > { new WriteThroughStruct <long> { Value = 5 } } }; FlatBufferSerializer serializer = new FlatBufferSerializer(option); byte[] buffer = new byte[1024]; serializer.Serialize(table, buffer); // parse var parsed1 = serializer.Parse <Table <IList <WriteThroughStruct <long> > > >(buffer); // mutate parsed1.Struct[0].Value = 300; Assert.Equal(300, parsed1.Struct[0].Value); // verify var parsed2 = serializer.Parse <Table <IList <WriteThroughStruct <long> > > >(buffer); Assert.Equal(300, parsed2.Struct[0].Value); }
public FlatBufferVectorTests() { var originalVector = new TableVector <string> { Vector = ExpectedStringContents.ToList() }; var originalIntVector = new TableVector <int> { Vector = ExpectedIntContents.ToList() }; Span <byte> buffer = new byte[1024 * 1024]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); var progressiveSerializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Progressive)); int bytesWritten = serializer.Serialize(originalVector, buffer); this.stringVector = serializer.Parse <TableVector <string> >(buffer.Slice(0, bytesWritten).ToArray()); this.progressiveStringVector = progressiveSerializer.Parse <TableVector <string> >(buffer.Slice(0, bytesWritten).ToArray()); bytesWritten = serializer.Serialize(originalIntVector, buffer); this.intVector = serializer.Parse <TableVector <int> >(buffer.Slice(0, bytesWritten).ToArray()); this.progressiveIntVector = progressiveSerializer.Parse <TableVector <int> >(buffer.Slice(0, bytesWritten).ToArray()); }
public void Success(FlatBufferDeserializationOption option) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); WriteThroughTable_NotRequired <IList <ValueStruct> > table = new() { Item = new List <ValueStruct> { new() { Value = 1 } } }; byte[] result = new byte[1024]; serializer.Serialize(table, result); var parsed = serializer.Parse <WriteThroughTable_NotRequired <IList <ValueStruct> > >(result); Assert.Equal(1, parsed.Item[0].Value); parsed.Item[0] = new ValueStruct { Value = 4 }; // Re-read and verify the in-struct writethrough succeeded. parsed = serializer.Parse <WriteThroughTable_NotRequired <IList <ValueStruct> > >(result); Assert.Equal(4, parsed.Item[0].Value); }
public void Success_NonNullable(FlatBufferDeserializationOption option) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); WriteThroughTable_Required <ValueStruct> table = new() { Item = new ValueStruct { Value = 1 } }; byte[] result = new byte[1024]; var code = serializer.Compile <WriteThroughTable_Required <ValueStruct> >().CSharp; serializer.Serialize(table, result); var parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct> >(result); Assert.Equal(1, parsed.Item.Value); parsed.Item = new ValueStruct { Value = 4 }; // Re-read and verify the in-struct writethrough succeeded. parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct> >(result); Assert.Equal(4, parsed.Item.Value); }
public void Success_Nullable(FlatBufferDeserializationOption option) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); WriteThroughTable_Required <ValueStruct?> table = new() { Item = new ValueStruct { Value = 1 } }; byte[] result = new byte[1024]; var code = serializer.Compile <WriteThroughTable_Required <ValueStruct?> >().CSharp; serializer.Serialize(table, result); var parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct?> >(result); Assert.Equal(1, parsed.Item.Value.Value); parsed.Item = new ValueStruct { Value = 4 }; // Re-read and verify the in-struct writethrough succeeded. parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct?> >(result); Assert.Equal(4, parsed.Item.Value.Value); var ex = Assert.Throws <InvalidOperationException>(() => parsed.Item = null); Assert.Equal( "Nullable object must have a value.", ex.Message); }
public void MemoryVector_LazyDeserialize() { RootTable <Memory <byte> > root = new RootTable <Memory <byte> >() { Vector = new Memory <byte>(new byte[100]) }; root.Vector.Span.Fill(1); byte[] buffer = new byte[1024]; var options = new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy); var serializer = new FlatBufferSerializer(options); serializer.Serialize(root, buffer.AsSpan()); var parsed1 = serializer.Parse <RootTable <Memory <byte> > >(buffer); var parsed2 = serializer.Parse <RootTable <Memory <byte> > >(buffer); Assert.AreEqual((byte)1, parsed1.Vector.Span[0]); Assert.AreEqual((byte)1, parsed2.Vector.Span[0]); // Asser that this change affects both objects. parsed1.Vector.Span[0] = 2; Assert.AreEqual((byte)2, parsed1.Vector.Span[0]); Assert.AreEqual((byte)2, parsed2.Vector.Span[0]); }
public void Parse_SixteenByte(bool marshal) { byte[] data = { 4, 0, 0, 0, 236, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 20, 0, 4, 0, }; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions { EnableValueStructMemoryMarshalDeserialization = marshal }); var parsed = serializer.Parse <SimpleTableAnything <SixteenByteStruct?> >(data); Assert.NotNull(parsed); Assert.NotNull(parsed.Item); Assert.Equal(1, parsed.Item.Value.A); Assert.Equal(2ul, parsed.Item.Value.B); Assert.Equal(marshal, serializer.Compile <SimpleTableAnything <SixteenByteStruct?> >().CSharp.Contains("MemoryMarshal.Cast")); }
/// <summary> /// In lazy deserialization, FlatSharp reads from the underlying buffer each time. No caching is done. This will be /// the fastest option if your access patterns are sparse and you touch each element only once. /// </summary> public static void LazyDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Lazy deserialization reads objects from vectors each time you ask for them. InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(!object.ReferenceEquals(index0_1, index0_2), "A different instance is returned each time from lazy vectors"); // Properties from tables and structs are cached after they are read. string name = parsed.Name; string name2 = parsed.Name; Debug.Assert( !object.ReferenceEquals(name, name2), "When reading table/struct properties Lazy parsing returns a different instance each time."); // Invalidate the whole buffer. Undefined behavior past here! Array.Fill(buffer, (byte)0); try { var whoKnows = parsed.ListVector[1]; Debug.Assert(false); } catch { // This can be any sort of exception. This behavior is undefined. } }
private InnerTable <T> SerializeAndParse <T>(FlatBufferDeserializationOption option, T item) { FlatBufferSerializer serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(option)); InnerTable <T> value = new InnerTable <T> { First = new FirstStruct { First = 1 }, Second = new SecondStruct { Second = 2, }, String = "Foo bar baz bat", Union = new FlatBufferUnion <FirstStruct, SecondStruct, string>(new SecondStruct { Second = 3 }), Vector = item, }; serializer.Serialize(value, InputBuffer); InnerTable <T> parsed = serializer.Parse <InnerTable <T> >(InputBuffer); Assert.Equal(1, parsed.First.First); Assert.Equal(2, parsed.Second.Second); Assert.Equal("Foo bar baz bat", parsed.String); Assert.Equal(3, parsed.Union.Value.Item2.Second); return(parsed); }
private void RunTest(FlatBufferDeserializationOption option) { Table table = new Table { Outer = new OuterStruct { InnerVirtual = new InnerStruct { A = 3 }, NonVirtualInner = new InnerStruct { A = 30 } } }; FlatBufferSerializer serializer = new FlatBufferSerializer(option); byte[] data = new byte[1024]; serializer.Serialize(table, data); var parsed = serializer.Parse <Table>(data); Assert.Equal(3, parsed.Outer.InnerVirtual.A); Assert.Equal(30, parsed.Outer.NonVirtualInner.A); }
private SimpleTable SerializeAndParse(FlatBufferSerializerOptions options, out WeakReference <byte[]> buffer) { SimpleTable table = new SimpleTable { String = "hi", Struct = new SimpleStruct { Byte = 1, Long = 2, Uint = 3 }, StructVector = new List <SimpleStruct> { new SimpleStruct { Byte = 4, Long = 5, Uint = 6 } }, }; var serializer = new FlatBufferSerializer(options); var rawBuffer = new byte[1024]; serializer.Serialize(table, rawBuffer); buffer = new WeakReference <byte[]>(rawBuffer); string csharp = serializer.Compile <SimpleTable>().CSharp; return(serializer.Parse <SimpleTable>(rawBuffer)); }
public static void Run() { TypeModelContainer container = TypeModelContainer.CreateDefault(); container.RegisterTypeFacade <long, DateTimeOffset, DateTimeOffsetTypeFacadeConverter>(); container.RegisterTypeFacade <byte[], Guid, GuidByteArrayConverter>(); var example = new FacadeExampleTable { Guid = Guid.NewGuid(), Timestamp = DateTimeOffset.UtcNow, }; FlatBufferSerializer serializer = new FlatBufferSerializer( new FlatBufferSerializerOptions(FlatBufferDeserializationOption.PropertyCache), container); byte[] destination = new byte[1024]; serializer.Serialize(example, destination); var parsed = serializer.Parse <FacadeExampleTable>(destination); Debug.Assert(parsed.Guid == example.Guid); Debug.Assert(parsed.Timestamp == example.Timestamp); }
public void SortedVectors(FlatBufferDeserializationOption option) { var builder = new FlatBuffers.FlatBufferBuilder(1024 * 1024); var strings = new List <string>(); var stringOffsets = new List <FlatBuffers.Offset <Oracle.SortedVectorStringTable> >(); List <int> ints = new List <int>(); var intOffsets = new List <FlatBuffers.Offset <Oracle.SortedVectorInt32Table> >(); List <double> doubles = new List <double>(); var doubleOffsets = new List <FlatBuffers.Offset <Oracle.SortedVectorDoubleTable> >(); const int Iterations = 1000; Random random = new Random(); for (int i = 0; i < Iterations; ++i) { string value = Guid.NewGuid().ToString(); strings.Add(value); stringOffsets.Add(Oracle.SortedVectorStringTable.CreateSortedVectorStringTable(builder, builder.CreateString(value))); } for (int i = 0; i < Iterations; ++i) { int value = random.Next(); ints.Add(value); intOffsets.Add(Oracle.SortedVectorInt32Table.CreateSortedVectorInt32Table(builder, value)); } for (int i = 0; i < Iterations; ++i) { double value = random.NextDouble() * random.Next(); doubles.Add(value); doubleOffsets.Add(Oracle.SortedVectorDoubleTable.CreateSortedVectorDoubleTable(builder, value)); } var table = Oracle.SortedVectorTest.CreateSortedVectorTest( builder, Oracle.SortedVectorInt32Table.CreateSortedVectorOfSortedVectorInt32Table(builder, intOffsets.ToArray()), Oracle.SortedVectorStringTable.CreateSortedVectorOfSortedVectorStringTable(builder, stringOffsets.ToArray()), Oracle.SortedVectorDoubleTable.CreateSortedVectorOfSortedVectorDoubleTable(builder, doubleOffsets.ToArray())); builder.Finish(table.Value); byte[] serialized = builder.SizedByteArray(); var serializer = new FlatBufferSerializer(option); var parsed = serializer.Parse <SortedVectorTest <SortedVectorItem <int> > >(serialized); VerifySorted(parsed.StringVector, new Utf8StringComparer(), strings, new List <string> { Guid.NewGuid().ToString(), "banana" }); VerifySorted(parsed.IntVector, Comparer <int> .Default, ints, new List <int> { -1, -3, 0 }); VerifySorted(parsed.Double, Comparer <double> .Default, doubles, new List <double> { Math.PI, Math.E, Math.Sqrt(2) }); }
/// <summary> /// In lazy deserialization, FlatSharp reads from the underlying buffer each time. No caching is done. This will be /// the fastest option if your access patterns are sparse and you touch each element only once. /// </summary> public static void LazyDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Lazy deserialization reads objects from vectors each time you ask for them. InnerTable index0_1 = parsed.ListVector ![0];
public IndexedVectorTests() { this.stringVectorSource = new TableVector <string> { Vector = new IndexedVector <string, VectorMember <string> >() }; this.intVectorSource = new TableVector <int> { Vector = new IndexedVector <int, VectorMember <int> >() }; this.stringKeys = new List <string>(); for (int i = 0; i < 10; ++i) { string key = i.ToString(); stringKeys.Add(key); this.stringVectorSource.Vector.AddOrReplace(new VectorMember <string> { Key = key, Value = Guid.NewGuid().ToString() }); this.intVectorSource.Vector.AddOrReplace(new VectorMember <int> { Key = i, Value = Guid.NewGuid().ToString() }); } this.stringVectorSource.Vector.Freeze(); this.intVectorSource.Vector.Freeze(); Span <byte> buffer = new byte[1024]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); var progressiveSerializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Progressive)); int bytesWritten = serializer.Serialize(this.stringVectorSource, buffer); this.stringVectorParsed = serializer.Parse <TableVector <string> >(buffer.Slice(0, bytesWritten).ToArray()); this.stringVectorProgressive = progressiveSerializer.Parse <TableVector <string> >(buffer.Slice(0, bytesWritten).ToArray()); bytesWritten = serializer.Serialize(this.intVectorSource, buffer); this.intVectorParsed = serializer.Parse <TableVector <int> >(buffer.Slice(0, bytesWritten).ToArray()); this.intVectorProgressive = progressiveSerializer.Parse <TableVector <int> >(buffer.Slice(0, bytesWritten).ToArray()); }
public void TestInitialize() { var originalVector = new TableVector { StringVector = ExpectedContents.ToList() }; Span <byte> buffer = new byte[1024]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy)); int bytesWritten = serializer.Serialize(originalVector, buffer); this.parsedVector = serializer.Parse <TableVector>(buffer.Slice(0, bytesWritten).ToArray()); }
private void VectorOfUnionTest <V>( FlatBufferDeserializationOption option, Func <V, FlatBufferUnion <string, Struct, TableWithKey <int> >[]> getItems) where V : class, new() { byte[] data = { 4, 0, 0, 0, 244, 255, 255, 255, 16, 0, 0, 0, // uoffset to discriminator vector 20, 0, 0, 0, // uoffset to offset vector 8, 0, // vtable 12, 0, 4, 0, 8, 0, 3, 0, 0, 0, // discriminator vector length 1, 2, 3, 0, // values + 1 byte padding 3, 0, 0, 0, // offset vector length 12, 0, 0, 0, // value 0 16, 0, 0, 0, // value 1 16, 0, 0, 0, // value 2 3, 0, 0, 0, // string length 102, 111, 111, 0, // foo + null terminator 3, 0, 0, 0, // struct value ('3') 248, 255, 255, 255, // table vtable offset 1, 0, 0, 0, // value of 'key' 8, 0, // table vtable start 8, 0, 0, 0, 4, 0, }; var serializer = new FlatBufferSerializer(option); V parsed = serializer.Parse <V>(data); var items = getItems(parsed); Assert.True(items[0].TryGet(out string str)); Assert.Equal("foo", str); Assert.True(items[1].TryGet(out Struct @struct)); Assert.Equal(3, @struct.Integer); Assert.True(items[2].TryGet(out TableWithKey <int> table)); Assert.Equal(1, table.Key); Assert.Null(table.Value); }
/// <summary> /// Greedy deserialization operates the same way that conventional serializers do. The entire buffer is traversed /// and the structure is copied into the deserialized object. This is the most straightforward way of using FlatSharp, /// because the results it gives are predictable, and require no developer cognitive overhead. However, it can be less efficient /// in cases where you do not need to access all data in the buffer. /// </summary> public static void GreedyDeserialization(DemoTable demo) { // Same as FlatBufferSerializer.Default var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); long originalSum = buffer.Sum(x => (long)x); var parsed = serializer.Parse <DemoTable>(buffer); // Fill array with 0. Source data is gone now, but we can still read the buffer because we were greedy! Array.Fill(buffer, (byte)0); InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(object.ReferenceEquals(index0_1, index0_2), "Greedy deserialization returns you the same instance each time"); // We cleared the data, but can still read the name. Greedy deserialization is easy! string name = parsed.Name; // By default, Flatsharp will not allow mutations to properties. You can learn more about this in the mutable example below. try { parsed.Name = "George Washington"; Debug.Assert(false); } catch (NotMutableException) { } try { parsed.ListVector.Clear(); Debug.Assert(false); } catch (NotSupportedException) { } }
private void RunSuccessTest <TTable, TStruct>() where TTable : class, IContextItem, IContextTable <TStruct>, new() where TStruct : class, IContextItem, new() { TTable table = new TTable(); byte[] data = new byte[1024]; foreach (FlatBufferDeserializationOption item in Enum.GetValues(typeof(FlatBufferDeserializationOption))) { var serializer = new FlatBufferSerializer(item); serializer.Serialize(table, data); TTable result = serializer.Parse <TTable>(data); Assert.IsNull(table.Context); Assert.AreEqual(item, result.Context.DeserializationOption); Assert.AreEqual(item, result.Struct.Context.DeserializationOption); Assert.IsFalse(object.ReferenceEquals(result.Context, result.Struct.Context)); } }
/// <summary> /// This example shows GreedyMutable deserialization. This is exactly the same as Greedy deserialization, but setters are generated for /// the objects, so vectors and properties are mutable in a predictable way. /// </summary> public static void GreedyMutableDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.GreedyMutable)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); long originalSum = buffer.Sum(x => (long)x); var parsed = serializer.Parse <DemoTable>(buffer); parsed.Name = "James Adams"; parsed.ListVector.Clear(); parsed.ListVector.Add(new InnerTable()); long newSum = buffer.Sum(x => (long)x); Debug.Assert( newSum == originalSum, "Changes to the deserialized objects are not written back to the buffer. You'll need to re-serialize it to a new buffer for that."); }
public void StringVector_GreedyDeserialize_NotMutable() { RootTable <IList <string> > root = new RootTable <IList <string> > { Vector = new List <string> { "one", "two", "three" } }; var options = new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy); FlatBufferSerializer serializer = new FlatBufferSerializer(options); byte[] buffer = new byte[100]; serializer.Serialize(root, buffer); var parsed = serializer.Parse <RootTable <IList <string> > >(buffer); Assert.AreEqual(typeof(ReadOnlyCollection <string>), parsed.Vector.GetType()); Assert.IsTrue(parsed.Vector.IsReadOnly); Assert.ThrowsException <NotSupportedException>(() => parsed.Vector.Add("four")); }
public void StringVector_GreedyDeserialize_Mutable() { RootTable <IList <string> > root = new RootTable <IList <string> > { Vector = new List <string> { "one", "two", "three" } }; var options = new FlatBufferSerializerOptions(FlatBufferDeserializationOption.GreedyMutable); FlatBufferSerializer serializer = new FlatBufferSerializer(options); byte[] buffer = new byte[100]; serializer.Serialize(root, buffer); var parsed = serializer.Parse <RootTable <IList <string> > >(buffer); Assert.AreEqual(typeof(List <string>), parsed.Vector.GetType()); Assert.IsFalse(parsed.Vector.IsReadOnly); // Shouldn't throw. parsed.Vector.Add("four"); }
/// <summary> /// The next step up in greediness is PropertyCache mode. In this mode, Flatsharp will cache the results of property accesses. /// So, if you read the results of FooObject.Property1 multiple times, the same value comes back each time. What this mode /// does not do is cache vectors. So reding FooObject.Vector[0] multiple times re-visits the buffer each time. /// </summary> public static void PropertyCacheDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.PropertyCache)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Properties from tables and structs are cached after they are read. string name = parsed.Name; string name2 = parsed.Name; Debug.Assert( object.ReferenceEquals(name, name2), "When reading table/struct properties, PropertyCache mode returns the same instance."); // PropertyCache deserialization doesn't cache the results of vector lookups. InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(!object.ReferenceEquals(index0_1, index0_2), "A different instance is returned each time from vectors in PropertyCache mode."); Debug.Assert(object.ReferenceEquals(parsed.ListVector, parsed.ListVector), "But the vector instance itself is the cached."); Debug.Assert(object.ReferenceEquals(index0_1.Fruit, index0_1.Fruit), "And the items returned from each vector exhibit property cache behavior"); // Invalidate the whole buffer. Undefined behavior past here! Array.Fill(buffer, (byte)0); try { var whoKnows = parsed.ListVector[1]; Debug.Assert(false); } catch { // This can be any sort of exception. This behavior is undefined. } }
private void FacadeTest <TUnderlyingType, TType, TConverter>( TUnderlyingType underlyingValue, TType value, TypeModelContainer container = null) where TConverter : struct, ITypeFacadeConverter <TUnderlyingType, TType> { if (container == null) { container = TypeModelContainer.CreateDefault(); container.RegisterTypeFacade <TUnderlyingType, TType, TConverter>(); } FlatBufferSerializer serializer = new FlatBufferSerializer( new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy), container); byte[] destination = new byte[1024]; byte[] destination2 = new byte[1024]; var compiled = serializer.Compile <ExtensionTable <TType> >(); var underlyingItem = new ExtensionTable <TUnderlyingType> { Item = underlyingValue }; var facadeItem = new ExtensionTable <TType> { Item = value }; serializer.Serialize(facadeItem, destination); serializer.Serialize(underlyingItem, destination2); Assert.True(destination.AsSpan().SequenceEqual(destination2)); var parsed = serializer.Parse <ExtensionTable <TType> >(destination); Assert.Equal(parsed.Item, value); Assert.Equal(serializer.GetMaxSize(facadeItem), serializer.GetMaxSize(underlyingItem)); }
/// <summary> /// Vector cache is a superset of PropertyCache. The difference is that when deserializing in VectorCache mode, FlatSharp /// will allocate a vector for you that gets lazily filled in as elements are accessed. This leads to some array allocations /// behind the scenes, since FlatSharp needs to know what objects have been returned for what indices. /// </summary> public static void VectorCacheDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.VectorCache)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Properties from tables and structs are cached after they are read. string name = parsed.Name; string name2 = parsed.Name; Debug.Assert( object.ReferenceEquals(name, name2), "When reading table/struct properties, PropertyCache mode returns the same instance."); // VectorCache deserialization guarantees only one object per index. InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(object.ReferenceEquals(index0_1, index0_2), "The same instance is returned each time from vectors in VectorCache mode."); Debug.Assert(object.ReferenceEquals(parsed.ListVector, parsed.ListVector), "And the vector instance itself is the same."); Debug.Assert(object.ReferenceEquals(index0_1.Fruit, index0_1.Fruit), "And the items returned from each vector exhibit property cache behavior"); }
static void Main(string[] args) { Upstream up = new Upstream(); up.Structure = new FSeed(); up.Structure.Data = new ConfigEntry[1]; var e0 = new ConfigEntry(); up.Structure.Data[0] = e0; e0.Tag = "stuff"; e0.Type = "string"; e0.Used = true; Console.WriteLine("test serializing up"); var testBuffer = new byte[1000]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Default)); var testLength = serializer.Serialize(up, testBuffer); Upstream up2 = serializer.Parse <Upstream>(testBuffer); Console.WriteLine("Starting Main"); // For some reason, I have to copy the args into a local array, or else they disappear int[] fileDescriptors = new int[2]; for (int i = 0; i < fileDescriptors.Length && i < args.Length; i++) { int n = ParsedFd(args[i]); Console.WriteLine(n); fileDescriptors[i] = n; } // Grab the FDs from the environment variables and translate to a IntPtr int fdNumIn = fileDescriptors[0]; SafeFileHandle inPipeHandle = new SafeFileHandle(new IntPtr(fdNumIn), true); int fdNumOut = fileDescriptors[1]; SafeFileHandle outPipeHandle = new SafeFileHandle(new IntPtr(fdNumOut), true); Console.WriteLine("GO_FUZZ_IN_FD: " + fdNumIn); Console.WriteLine("GO_FUZZ_OUT_FD: " + fdNumOut); string[] commName = new string[4]; for (int i = 2; i < args.Length; i++) { commName[i - 2] = args[i]; Console.WriteLine(("comm" + (i - 2)) + ": " + commName[(i - 2)]); } const int MaxInputSize = 1 << 24; const int ReturnResultSize = 1 << 25; const int CoverSize = 64 << 10; const int SonarRegionSize = 1 << 20; // Use the filehandles Stream inStream = new FileStream(inPipeHandle, FileAccess.Read); Console.WriteLine("created inStream"); Stream outStream = new FileStream(outPipeHandle, FileAccess.Write); Console.WriteLine("created outStream"); MemoryMappedFileSecurity security = new MemoryMappedFileSecurity(); security.AddAccessRule(new AccessRule <MemoryMappedFileRights>(("Everyone"), MemoryMappedFileRights.FullControl, AccessControlType.Allow)); Console.WriteLine("created security"); MemoryMappedFile comm0 = MemoryMappedFile.OpenExisting(commName[0], MemoryMappedFileRights.ReadWrite, HandleInheritability.Inheritable); Console.WriteLine("created comm0"); var comm0Accessor = comm0.CreateViewAccessor(0, MaxInputSize); Console.WriteLine("created comm0Accessor"); MemoryMappedFile comm1 = MemoryMappedFile.OpenExisting(commName[1], MemoryMappedFileRights.ReadWrite, HandleInheritability.Inheritable); Console.WriteLine("created comm1"); var comm1Accessor = comm1.CreateViewAccessor(0, ReturnResultSize); Console.WriteLine("created comm1Accessor"); MemoryMappedFile comm2 = MemoryMappedFile.OpenExisting(commName[2], MemoryMappedFileRights.ReadWrite, HandleInheritability.Inheritable); Console.WriteLine("created comm2"); var comm2Accessor = comm2.CreateViewAccessor(0, CoverSize); Console.WriteLine("created comm2Accessor"); //var comm3Stream = new FileStream(commNames[3], FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); //Console.WriteLine("created comm3Stream"); MemoryMappedFile comm3 = MemoryMappedFile.OpenExisting(commName[3], MemoryMappedFileRights.ReadWrite, HandleInheritability.Inheritable); Console.WriteLine("created comm3"); var comm3Accessor = comm3.CreateViewAccessor(0, SonarRegionSize); Console.WriteLine("created comm3Accessor"); char[] inPipeBuffer = new char[10]; char[] outputBuffer = new char[24]; char[] returnLengthBuffer = new char[8]; StreamReader inPipeReader = new StreamReader(inStream); StreamWriter outputWriter = new StreamWriter(outStream); while (true) { inPipeReader.Read(inPipeBuffer, 0, inPipeBuffer.Length); int fnidx = inPipeBuffer[0]; fnidx += inPipeBuffer[1] << 8; Console.WriteLine("fnidx: " + fnidx); char[] lengthBuffer = new char[8]; for (int i = 2; i < inPipeBuffer.Length; i++) { lengthBuffer[i - 2] = inPipeBuffer[i]; } Int64 inputLength = Deserialize64(lengthBuffer); Console.WriteLine("input length: " + inputLength); // read inputBuffer data from comm0 var inputBuffer = new byte[inputLength]; comm0Accessor.ReadArray(0, inputBuffer, 0, (int)inputLength); for (int i = 0; i < inputLength; i++) { inputBuffer[i] = comm0Accessor.ReadByte(i); } var inputString = Encoding.UTF8.GetString(inputBuffer); Console.WriteLine("downstream: "); Console.WriteLine(inputString); //var downstream = Downstream.Deserialize(inputString); var downstream = FlatBufferSerializer.Default.Parse <Downstream>(inputBuffer); Console.WriteLine("downstream deserialized"); var seed = downstream.Seed; var entries = seed.Data; ConfigEntry entry = null; if (entries.Count >= 1) { entry = entries[0]; } else { Console.WriteLine("zero entries!"); } var value = entry.Value; Console.WriteLine("got entry value: " + value); Int64 res = 0; Int64 ns; Int64 sonar = 0; Int64 returnLength = 0; // Start the clock var nsStart = DateTime.UtcNow.Ticks; // Actually run the function to fuzz Console.WriteLine("BrokenMethod()"); Console.WriteLine(BrokenMethod(value)); ns = DateTime.UtcNow.Ticks - nsStart; Console.WriteLine("ns: " + ns); char[] resBuffer = new char[8]; char[] nsBuffer = new char[8]; char[] sonarBuffer = new char[8]; Serialize56(resBuffer, res); Serialize56(nsBuffer, ns); Serialize56(sonarBuffer, sonar); Console.WriteLine("instantiating upstream"); Upstream upstream = new Upstream(); upstream.Structure = new FSeed(); upstream.Structure.Data = new ConfigEntry[1]; var upEntry = upstream.Structure.Data[0]; upEntry.Tag = "stuff"; upEntry.Type = "string"; upEntry.Used = true; Console.WriteLine("serializing upstream"); int maxReturnSize = FlatBufferSerializer.Default.GetMaxSize(upstream); var returnBuffer = new byte[maxReturnSize]; returnLength = FlatBufferSerializer.Default.Serialize(upstream, returnBuffer); Console.WriteLine("return length: " + returnLength); Serialize56(returnLengthBuffer, returnLength); for (int i = 0; i < 8; i++) { Console.WriteLine("returnLengthBuffer: " + (byte)returnLengthBuffer[i]); comm1Accessor.Write(i, returnLengthBuffer[i]); } for (int i = 0; i < returnLength; i++) { comm1Accessor.Write(i + 8, returnBuffer[i]); } comm1Accessor.Flush(); Console.WriteLine("wrote to comm1Accessor"); for (int i = 0; i < 8; i++) { outputBuffer[i] = resBuffer[i]; outputBuffer[i + 8] = nsBuffer[i]; outputBuffer[i + 16] = sonarBuffer[i]; } outputWriter.Write(outputBuffer, 0, outputBuffer.Length); outputWriter.Flush(); Console.WriteLine("wrote outputbuffer"); } }
static void Test(FlatBufferDeserializationOption option) { var table = new Table <WriteThroughStruct> { Struct = new WriteThroughStruct { Value = new OtherStruct { Prop1 = 10, Prop2 = 10 }, ValueStruct = new() { Value = 3, } } }; FlatBufferSerializer serializer = new FlatBufferSerializer(option); byte[] buffer = new byte[1024]; serializer.Serialize(table, buffer); // parse var parsed1 = serializer.Parse <Table <WriteThroughStruct> >(buffer); // mutate Assert.Equal(10, parsed1.Struct.Value.Prop1); Assert.Equal(10, parsed1.Struct.Value.Prop2); Assert.Equal(3, parsed1.Struct.ValueStruct.Value); parsed1.Struct.Value = new OtherStruct { Prop1 = 300, Prop2 = 300 }; parsed1.Struct.ValueStruct = new() { Value = -1 }; Assert.Equal(300, parsed1.Struct.Value.Prop1); Assert.Equal(300, parsed1.Struct.Value.Prop2); Assert.Equal(-1, parsed1.Struct.ValueStruct.Value); // verify, set to null var parsed2 = serializer.Parse <Table <WriteThroughStruct> >(buffer); Assert.Equal(300, parsed2.Struct.Value.Prop1); Assert.Equal(300, parsed2.Struct.Value.Prop2); Assert.Equal(-1, parsed2.Struct.ValueStruct.Value); parsed2.Struct.Value = null !; if (option == FlatBufferDeserializationOption.Progressive) { // we are null temporarily until we re-parse. Assert.Null(parsed2.Struct.Value); } else if (option == FlatBufferDeserializationOption.Lazy) { // lazy write through clears it out. Assert.Equal(0, parsed2.Struct.Value.Prop1); Assert.Equal(0, parsed2.Struct.Value.Prop2); } else { Assert.False(true); } // verify, set to null var parsed3 = serializer.Parse <Table <WriteThroughStruct> >(buffer); Assert.Equal(0, parsed3.Struct.Value.Prop1); Assert.Equal(0, parsed3.Struct.Value.Prop2); } Test(FlatBufferDeserializationOption.Progressive); Test(FlatBufferDeserializationOption.Lazy); }
public static void Run() { FooBarContainer container = new FooBarContainer { fruit = Fruit.Pears, initialized = true, location = "location", list = new List <FooBar> { new FooBar { name = "name", postfix = 1, rating = 3, sibling = new Bar { ratio = 3.14f, size = ushort.MaxValue, time = int.MinValue, // Nested structs are not intended to have null values, // but it is possible due to FlatSharp modeling // them as reference types. However, null structs // do not cause a problem when serializing or parsing. parent = null !, } } }, }; // Simple use case: make a deep copy of an object you're using. var copy = new FooBarContainer(container); Debug.Assert(!object.ReferenceEquals(copy.list, container.list), "A new list is created"); for (int i = 0; i < container.list.Count; ++i) { var originalItem = container.list[i]; Debug.Assert(copy.list is not null); var copyItem = copy.list[i]; Debug.Assert(!object.ReferenceEquals(copyItem, originalItem)); } // Now let's look at how this can be useful when operating on deserialized objects. var serializer = new FlatBufferSerializer(FlatBufferDeserializationOption.Lazy); byte[] data = new byte[1024]; serializer.Serialize(container, data); var deserialized = serializer.Parse <FooBarContainer>(data); // Take a deserialized item and "upcast" it back to the original type. // This performs a full traversal of the object and allows the underlying buffer to be reused. Debug.Assert(deserialized.GetType() != container.GetType(), "The deserialized type is a subclass of the FooBarContainer type"); copy = new FooBarContainer(deserialized); Debug.Assert(copy.GetType() == container.GetType(), "By using the copy constructor, we can get an instance of the original type."); // Next: Some deserialization modes, such as Lazy, don't permit mutation of the object. // Using the copy constructor can convert this to an object that we can mutate! try { // will throw deserialized.fruit = Fruit.Apples; Debug.Assert(false); } catch { } // Modifying the copy is just fine, though. copy.fruit = Fruit.Apples; }