~ruther/NosSmooth

ref: e67bb2bac9b1f0338596d5f2dfdf2508e7dee36b NosSmooth/Packets/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/ListInlineConverterGenerator.cs -rw-r--r-- 5.6 KiB
e67bb2ba — Rutherther Merge pull request #47 from Rutherther/feat/pass-nullable 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//
//  ListInlineConverterGenerator.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.CodeDom.Compiler;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using NosSmooth.PacketSerializersGenerator.Errors;
using NosSmooth.PacketSerializersGenerator.Extensions;

namespace NosSmooth.PacketSerializersGenerator.InlineConverterGenerators;

/// <inheritdoc/>
public class ListInlineConverterGenerator : IInlineConverterGenerator
{
    private readonly InlineTypeConverterGenerator _inlineConverters;
    private readonly List<ITypeSymbol> _listTypes;

    /// <summary>
    /// Initializes a new instance of the <see cref="ListInlineConverterGenerator"/> class.
    /// </summary>
    /// <param name="inlineConverters">The inline converter that is used for converting the values of the list.</param>
    public ListInlineConverterGenerator(InlineTypeConverterGenerator inlineConverters)
    {
        _inlineConverters = inlineConverters;
        _listTypes = new List<ITypeSymbol>();
    }

    /// <inheritdoc />
    public bool ShouldHandle(TypeSyntax? typeSyntax, ITypeSymbol? typeSymbol)
        => typeSymbol?.Name == "IReadOnlyList";

    /// <inheritdoc />
    public IError? GenerateSerializerPart
    (
        IndentedTextWriter textWriter,
        string variableName,
        TypeSyntax? typeSyntax,
        ITypeSymbol? typeSymbol
    )
    {
        ITypeSymbol genericArgument = ((INamedTypeSymbol)typeSymbol!).TypeArguments[0];
        textWriter.WriteMultiline
        (
            @$"
        if ({variableName} is null)
        {{
            builder.Append('-');
        }}
        else
        {{
            foreach (var item in {variableName})
            {{
                if (!builder.PushPreparedLevel())
                {{
                    return new ArgumentInvalidError(nameof(builder), ""The string builder has to have a prepared level for all lists."");
                }}

"
        );
        var error = _inlineConverters.Serialize(textWriter, "item", null, genericArgument);
        if (error is not null)
        {
            return error;
        }

        textWriter.WriteMultiline(@"
                builder.PopLevel();
            }
        }
"
        );
        return null;
    }

    /// <inheritdoc />
    public IError? CallDeserialize(IndentedTextWriter textWriter, TypeSyntax? typeSyntax, ITypeSymbol? typeSymbol, bool nullable)
    {
        ITypeSymbol genericArgument = ((INamedTypeSymbol)typeSymbol!).TypeArguments[0];
        if (_listTypes.All
            (
                x => x.ToString() != genericArgument!.ToString()
                    || ((x.IsNullable() ?? false) && (!genericArgument.IsNullable() ?? false))
            ))
        {
            _listTypes.Add(genericArgument!);
        }

        textWriter.WriteLine
            ($"{Constants.HelperClass}.{GetMethodName(genericArgument, nullable)}(typeConverter, _stringSerializer, ref stringEnumerator);");
        return null;
    }

    private string GetMethodName(ITypeSymbol genericArgumentType, bool nullable)
    {
        return
            $"ParseList{genericArgumentType.ToString().TrimEnd('?').Replace('.', '_').Replace('<', '_').Replace('>', '_')}{((genericArgumentType.IsNullable() ?? false) ? "Nullable" : string.Empty)}{(nullable ? "NullableSupport" : string.Empty)}";
    }

    private void GenerateHelperMethods(IndentedTextWriter textWriter, bool nullable)
    {
        foreach (var type in _listTypes)
        {
            textWriter.WriteLine
            (
                @$"
public static Result<IReadOnlyList<{type.GetActualType()}>> {GetMethodName(type, nullable)}(IStringConverter typeConverter, IStringSerializer _stringSerializer, ref PacketStringEnumerator stringEnumerator)
{{
    var data = new List<{type.GetActualType()}>();

    while (!(stringEnumerator.IsOnLastToken() ?? false))
    {{
        if (!stringEnumerator.PushPreparedLevel())
        {{
            return new ArgumentInvalidError(nameof(stringEnumerator), ""The string enumerator has to have a prepared level for all lists."");
        }}

        var result = "
            );
            /*var error = */_inlineConverters.CallDeserialize(textWriter, null, type, nullable); // TODO handle error

            textWriter.WriteMultiline(@$"

        // If we know that we are not on the last token in the item level, just skip to the end of the item.
        // Note that if this is the case, then that means the converter is either corrupted
        // or the packet has more fields.
        while (stringEnumerator.IsOnLastToken() == false)
        {{
            stringEnumerator.GetNextToken(out _);
        }}

        stringEnumerator.PopLevel();
        if (!result.IsSuccess)
        {{
            return Result<IReadOnlyList<{type}>>.FromError(new ListSerializerError(result, data.Count), result);
        }}

"
            );

            if (!(type.IsNullable() ?? false))
            {
                textWriter.WriteMultiline
                (
                    $@"
if (result.Entity is null)
{{
    return new DeserializedValueNullError(typeof({type.ToString().TrimEnd('?')}));
}}
"
                );
            }
            textWriter.WriteLine($"data.Add(({type.GetActualType()})result.Entity);");
            textWriter.WriteLine("}");
            textWriter.WriteLine("return data;");
            textWriter.WriteLine("}");
        }
    }

    /// <inheritdoc />
    public void GenerateHelperMethods(IndentedTextWriter textWriter)
    {
        GenerateHelperMethods(textWriter, true);
        GenerateHelperMethods(textWriter, false);
    }

}
Do not follow this link