Coder Social home page Coder Social logo

tinyhand's People

Contributors

archi-doc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

chandanksingh

tinyhand's Issues

Doesn't work out of the box

  1. In VS2019 create a new .net 5 console app
  2. Copy-paste the sample code from the getting started section
    (I uploaded the code here)
  3. Run
  4. Exception:
    Tinyhand.TinyhandException
    HResult=0x80131500
    Message=Failed to serialize TinyhandBug.MyClass value.
    Source=Tinyhand
    StackTrace:
    at Tinyhand.TinyhandSerializer.Serialize[T](T value, TinyhandSerializerOptions options, CancellationToken cancellationToken)
    at TinyhandBug.Program.Main(String[] args) in C:\Users\marhoily\source\repos\TinyhandBug\TinyhandBug\Program.cs:line 14

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:

  1. No partial class seems to be generated
  2. When I enable <TreatWarningsAsErrors>true</TreatWarningsAsErrors> I get the following error
    An instance of analyzer Tinyhand.Generator.TinyhandGenerator cannot be created from C:\Users\marhoily.nuget\packages\tinyhand\0.24.1\analyzers\dotnet\cs\TinyhandGenerator.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..

NativeAOT: This operation is only valid on generic types

Is 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.

Assembly names with non-alpha characters causing invalid classname in generated code

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.

Deserializing list results in 'Index was out of range'

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;
}

Handling multiple enum instances

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).

Source Generator fails when a property is named 'System'

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.