archi-doc / tinyhand Goto Github PK
View Code? Open in Web Editor NEWTiny and simple data format/serializer.
License: MIT License
Tiny and simple data format/serializer.
License: MIT License
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
FormatterNotRegisteredException: TinyhandBug.MyClass is not registered in resolver: Tinyhand.Resolvers.StandardResolver
Observations:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
I get the following errorIs being compatible with ahead-of-time compilation a goal of Tinyhand? The following works fine in Debug & Release:
using Tinyhand;
using ns;
var engineTinyHandOptions = Tinyhand.TinyhandSerializerOptions.Standard;
// Create simple test object, serialize to file
var obj = new Test() { Str = "TestString", i = 1 };
var bytes = Tinyhand.TinyhandSerializer.Serialize<Test>(obj, engineTinyHandOptions);
File.WriteAllBytes("out.th", bytes);
// Deserialise from file
FileStream stream = new FileStream("out.th", FileMode.Open);
var returnObject = Tinyhand.TinyhandSerializer.Deserialize<Test>(stream, engineTinyHandOptions);
Console.WriteLine(returnObject.Str);
stream.Close();
namespace ns
{
[Tinyhand.TinyhandObject(ImplicitKeyAsName = true)]
public partial class Test
{
public string Str;
public int i;
}
}
However if I publish as a self-contained executable using NativeAOT I get the following error at runtime:
Unhandled Exception: Tinyhand.TinyhandException: Failed to serialize ns.Test value.
---> System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
---> System.InvalidOperationException: This operation is only valid on generic types.
at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.GetGenericTypeDefinition() + 0x33
at System.Reflection.Runtime.TypeInfos.NativeFormat.NativeFormatRuntimeNamedTypeInfo.GetGenericTypeDefinition() + 0xe9
at Tinyhand.Resolvers.GeneratedResolver.TryGetFormatter[T]() + 0x57
at Tinyhand.Resolvers.StandardResolver.FormatterCache`1..cctor() + 0xb4
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xd6
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x16f
at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext*, Object) + 0xd
at Tinyhand.Resolvers.StandardResolver.TryGetFormatter[T]() + 0x11
at Tinyhand.ResolverExtensions.GetFormatter[T](IFormatterResolver) + 0x39
at Tinyhand.TinyhandSerializer.Serialize[T](T, TinyhandSerializerOptions, CancellationToken) + 0x164
--- End of inner exception stack trace ---
at Tinyhand.TinyhandSerializer.Serialize[T](T, TinyhandSerializerOptions, CancellationToken) + 0x21e
at <Program>$.<Main>$(String[]) + 0x74
at ConsoleApp1!<BaseAddress>+0x3427ba
Changing the resolver (e.g. to only use GeneratedResolver, or a CompositeResolver) doesn't appear to help. This is using the latest version of Tinyhand from nuget (0.20.1). Perhaps we are missing a .IsGenericType
check somewhere?
Supporting AOT platforms (e.g. iOS, consoles) is a goal of the MessagePack-CSharp project, albeit using their custom mpc.exe solution for generating code, rather than using a source generator.
Quick one - an assembly name with a non-alpha character e.g.:
<AssemblyName>My.Project</AssemblyName>
Will result in an error, as the generated code contains an invalid class name:
public static class TinyhandModule_My.Project
It's easy enough to work around, but I'm guessing these characters should be substituted or stripped out of the generated classname.
If we define the following, where the outer class contains a list of the inner class:
[TinyhandObject]
public partial class OuterClass
{
[Key(1)]
public List<MyInnerClass> MyList;
}
[TinyhandObject]
public partial class MyInnerClass
{
[Key(2)]
public int i;
}
And use as follows, we get an error when deserializing (Index was out of range
):
// Instantiate
var test = new OuterClass();
test.MyList = new List<MyInnerClass>() { new MyInnerClass { i = 25 } };
// Serialize to bytes
var bytes = Tinyhand.TinyhandSerializer.Serialize<OuterClass>(test);
// Deserialize from bytes - fails here
var test2 = Tinyhand.TinyhandSerializer.Deserialize<OuterClass>(bytes);
The issue with the generated code is here, where the list is instantiated with a capacity but the list.Count is still zero, so the assignment fails:
internal static System.Collections.Generic.List<ConsoleApp1.MyInnerClass>? DeserializeList_0000(ref TinyhandReader reader, TinyhandSerializerOptions options)
{
var len = reader.ReadArrayHeader();
var list = new System.Collections.Generic.List<ConsoleApp1.MyInnerClass>(len);
options.Security.DepthStep(ref reader);
try
{
for (int i = 0; i < len; i++)
{
reader.CancellationToken.ThrowIfCancellationRequested();
list[i] = options.DeserializeAndReconstruct<ConsoleApp1.MyInnerClass>(ref reader); // Fails here as list.Count == 0
}
}
finally
{
reader.Depth--;
}
return list;
}
Having more than one instance of an enum within a class causes syntax errors in the generated code, e.g.:
public enum MyEnum { One, Two, Three }
[TinyhandObject]
public partial class TestClass
{
[Key(1)]
public MyEnum item1;
[Key(2)]
public MyEnum item2;
}
Throws error A local variable or function named 'ev' is already defined in this scope
due to the following:
public void Serialize(ref TinyhandWriter writer, TinyhandSerializerOptions options)
{
writer.WriteArrayHeader(3);
writer.WriteNil();
var ev = this.item1; writer.Write(Unsafe.As<ConsoleApp1.MyEnum, int>(ref ev));
var ev = this.item2; writer.Write(Unsafe.As<ConsoleApp1.MyEnum, int>(ref ev));
}
Suspect EnumCoder.cs needs to be smarter about variable names, perhaps incrementing (ev1, ev2 etc).
The following fails to compile:
namespace ns
{
[Tinyhand.TinyhandObject(ImplicitKeyAsName = true)]
public partial class Test
{
public MyClass[] array = new MyClass[10];
public int System;
}
[Tinyhand.TinyhandObject(ImplicitKeyAsName = true)]
public partial class MyClass
{
public int ii;
}
}
Build error from the generated code: 'int' does not contain a definition for 'Array' and no accessible extension method 'Array' accepting a first argument of type 'int' could be found
It appears the compiler is getting confused between the property named 'System' and the System namespace, e.g.:
if (key == 0x7961727261)
{
deserializedFlag[0] = true;
if (!reader.TryReadNil())
{
this.array = global::Tinyhand.Formatters.Generated.DeserializeArray_0000(ref reader, options) ?? System.Array.Empty<ns.MyClass>();
}
else
{
this.array = System.Array.Empty<ns.MyClass>();
}
}
Suspect we need to add the global::
prefix to the System.Array
references in the generated code.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.