From aa03d610232040d1c7851a0eee5d00df0e50eea4 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozlenko Date: Sun, 1 Dec 2024 01:53:26 -0500 Subject: [PATCH] Support writing records with skipped fields in generated code --- Directory.Packages.props | 3 +- ....Tabular.Analyzers.CSharp.UnitTests.csproj | 1 - ...ax.Formats.Tabular.Analyzers.CSharp.csproj | 3 - .../SourceTextBuilder.cs | 75 --- .../SourceTextWriter.cs | 72 +++ .../TabularFieldMapping.cs | 15 +- .../TabularHandlerEmitter.Builders.cs | 601 ++++++++---------- .../TabularHandlerEmitter.cs | 65 +- .../TabularHandlerParser.cs | 58 +- .../TabularRecordMapping.cs | 3 +- .../TypeMemberAccess.cs | 14 - .../TabularReaderTests.cs | 4 +- .../Converters/TabularBase16ArrayConverter.cs | 2 +- .../Converters/TabularBase64ArrayConverter.cs | 2 +- .../Converters/TabularUriConverter.cs | 2 +- .../Handlers/TabularArrayHandler`1.cs | 4 +- .../{ => Primitives}/TabularFieldInfo.cs | 2 +- .../{ => Primitives}/TabularParserState.cs | 2 +- .../{ => Primitives}/TabularParsingArea.cs | 2 +- .../{ => Primitives}/TabularParsingMode.cs | 2 +- .../{ => Primitives}/TabularSearchValues.cs | 2 +- .../{ => Primitives}/TabularSeparator.cs | 2 +- .../{ => Primitives}/TabularTextInfo.cs | 2 +- src/Addax.Formats.Tabular/TabularDialect.cs | 1 + src/Addax.Formats.Tabular/TabularFormatter.cs | 1 + src/Addax.Formats.Tabular/TabularParser.cs | 1 + src/Addax.Formats.Tabular/TabularReader.cs | 7 +- .../TabularRegistry.T.cs | 2 +- 28 files changed, 438 insertions(+), 512 deletions(-) delete mode 100644 src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextBuilder.cs create mode 100644 src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextWriter.cs delete mode 100644 src/Addax.Formats.Tabular.Analyzers.CSharp/TypeMemberAccess.cs rename src/Addax.Formats.Tabular/{ => Primitives}/TabularFieldInfo.cs (94%) rename src/Addax.Formats.Tabular/{ => Primitives}/TabularParserState.cs (85%) rename src/Addax.Formats.Tabular/{ => Primitives}/TabularParsingArea.cs (83%) rename src/Addax.Formats.Tabular/{ => Primitives}/TabularParsingMode.cs (79%) rename src/Addax.Formats.Tabular/{ => Primitives}/TabularSearchValues.cs (96%) rename src/Addax.Formats.Tabular/{ => Primitives}/TabularSeparator.cs (76%) rename src/Addax.Formats.Tabular/{ => Primitives}/TabularTextInfo.cs (91%) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8732b26..ad5c9b9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,8 +1,7 @@ - - + \ No newline at end of file diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests.csproj b/src/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests.csproj index e3d3f68..d56be8b 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests.csproj +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests/Addax.Formats.Tabular.Analyzers.CSharp.UnitTests.csproj @@ -6,7 +6,6 @@ false - diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/Addax.Formats.Tabular.Analyzers.CSharp.csproj b/src/Addax.Formats.Tabular.Analyzers.CSharp/Addax.Formats.Tabular.Analyzers.CSharp.csproj index 8d71d97..455eb85 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/Addax.Formats.Tabular.Analyzers.CSharp.csproj +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/Addax.Formats.Tabular.Analyzers.CSharp.csproj @@ -7,9 +7,6 @@ cs - - all - all diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextBuilder.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextBuilder.cs deleted file mode 100644 index 4abe852..0000000 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextBuilder.cs +++ /dev/null @@ -1,75 +0,0 @@ -// (c) Oleksandr Kozlenko. Licensed under the MIT license. - -using System; -using System.Diagnostics; -using System.IO; -using System.Text; -using Microsoft.CodeAnalysis.Text; - -namespace Addax.Formats.Tabular.Analyzers.CSharp -{ - internal sealed class SourceTextBuilder : IDisposable - { - private readonly MemoryStream _memoryStream = new MemoryStream(); - private readonly StreamWriter _streamWriter; - private readonly Encoding _encoding; - private readonly int _indentSize; - private readonly char _indentChar; - - private int _indentLevel; - - public SourceTextBuilder(char indentChar, int indentSize, Encoding encoding) - { - Debug.Assert(indentSize >= 0); - Debug.Assert(encoding != null); - - _indentChar = indentChar; - _indentSize = indentSize; - _encoding = encoding; - _streamWriter = new StreamWriter(_memoryStream, _encoding); - } - - public void Dispose() - { - _streamWriter.Dispose(); - } - - public void Append(string value = null) - { - if (!string.IsNullOrEmpty(value)) - { - var indentValue = _indentLevel * _indentSize; - - for (var i = 0; i < indentValue; i++) - { - _streamWriter.Write(_indentChar); - } - - _streamWriter.WriteLine(value); - } - else - { - _streamWriter.WriteLine(); - } - } - - public SourceText ToSourceText() - { - _streamWriter.Flush(); - - return SourceText.From(_memoryStream, _encoding, canBeEmbedded: true); - } - - public int IndentLevel - { - get - { - return _indentLevel; - } - set - { - _indentLevel = value; - } - } - } -} diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextWriter.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextWriter.cs new file mode 100644 index 0000000..10b419a --- /dev/null +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/SourceTextWriter.cs @@ -0,0 +1,72 @@ +// (c) Oleksandr Kozlenko. Licensed under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.CodeAnalysis.Text; + +namespace Addax.Formats.Tabular.Analyzers.CSharp +{ + internal sealed class SourceTextWriter : IDisposable + { + private readonly MemoryStream _memoryStream = new MemoryStream(); + private readonly StreamWriter _streamWriter; + private readonly char _indentChar; + private readonly int _indentSize; + + public SourceTextWriter(Encoding encoding, char indentChar, int indentSize) + { + Debug.Assert(encoding != null); + Debug.Assert(indentSize >= 0); + + _streamWriter = new StreamWriter(_memoryStream, encoding); + _indentChar = indentChar; + _indentSize = indentSize; + } + + public void Dispose() + { + _streamWriter.Dispose(); + } + + public void WriteLine(string value) + { + Debug.Assert(value != null); + + var indentation = Indent * _indentSize; + + for (var i = 0; i < indentation; i++) + { + _streamWriter.Write(_indentChar); + } + + _streamWriter.WriteLine(value); + } + + public void WriteLine() + { + _streamWriter.WriteLine(); + } + + public SourceText ToSourceText() + { + _streamWriter.Flush(); + + return SourceText.From(_memoryStream, _streamWriter.Encoding, canBeEmbedded: true); + } + + public void Reset() + { + Indent = 0; + + _memoryStream.SetLength(0); + } + + public int Indent + { + get; + set; + } + } +} diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularFieldMapping.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularFieldMapping.cs index 65fbbde..cc47ddf 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularFieldMapping.cs +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularFieldMapping.cs @@ -11,13 +11,15 @@ internal readonly struct TabularFieldMapping public readonly string MemberName; public readonly string ValueTypeName; public readonly string ConverterTypeName; - public readonly TypeMemberAccess MemberAccess; - public readonly bool AsNullableT; + public readonly bool SupportsWriting; + public readonly bool SupportsReading; + public readonly bool IsNullableT; public TabularFieldMapping( string memberName, - TypeMemberAccess memberAccess, - bool asNullableT, + bool supportsReading, + bool supportsWriting, + bool isNullableT, string valueTypeName, string converterTypeName, SyntaxToken? fieldNameLiteral) @@ -26,8 +28,9 @@ public TabularFieldMapping( Debug.Assert(valueTypeName != null); MemberName = memberName; - MemberAccess = memberAccess; - AsNullableT = asNullableT; + SupportsReading = supportsReading; + SupportsWriting = supportsWriting; + IsNullableT = isNullableT; ValueTypeName = valueTypeName; ConverterTypeName = converterTypeName; FieldNameLiteral = fieldNameLiteral; diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.Builders.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.Builders.cs index 4bc0cf0..357131f 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.Builders.cs +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.Builders.cs @@ -4,65 +4,66 @@ namespace Addax.Formats.Tabular.Analyzers.CSharp { internal partial class TabularHandlerEmitter { - private static void BuildHandlerRegistratorSource(SourceTextBuilder builder, string typeName, int handlerCount) + private static void BuildRegistryInitializerSource(SourceTextWriter writer, string typeName, int handlerCount) { - builder.Append("// "); - builder.Append(); - builder.Append("namespace Addax.Formats.Tabular.Handlers;"); - builder.Append(); - builder.Append($"[global::System.CodeDom.Compiler.GeneratedCode(\"{s_assemblyInfo.Name}\", \"{s_assemblyInfo.Version}\")]"); - builder.Append($"file static class {typeName}"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("[global::System.Runtime.CompilerServices.ModuleInitializer]"); - builder.Append("public static void Initialize()"); - builder.Append("{"); - builder.IndentLevel++; + writer.WriteLine("// "); + writer.WriteLine(); + writer.WriteLine("namespace Addax.Formats.Tabular.Handlers;"); + writer.WriteLine(); + writer.WriteLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"{s_assemblyInfo.Name}\", \"{s_assemblyInfo.Version}\")]"); + writer.WriteLine($"file static class {typeName}"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("[global::System.Runtime.CompilerServices.ModuleInitializer]"); + writer.WriteLine("public static void Initialize()"); + writer.WriteLine("{"); + writer.Indent++; for (var i = 0; i < handlerCount; i++) { - builder.Append($"RegisterHandler(new global::Addax.Formats.Tabular.Handlers.Handler{i}());"); + writer.WriteLine($"RegisterHandler(new global::Addax.Formats.Tabular.Handlers.Handler{i}());"); } - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - builder.Append("private static void RegisterHandler(global::Addax.Formats.Tabular.TabularHandler handler)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("global::Addax.Formats.Tabular.TabularRegistry.Handlers[typeof(T)] = handler;"); - builder.IndentLevel--; - builder.Append("}"); - builder.IndentLevel--; - builder.Append("}"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine("private static void RegisterHandler(global::Addax.Formats.Tabular.TabularHandler handler)"); + writer.Indent++; + writer.WriteLine("where T : notnull"); + writer.Indent--; + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("global::Addax.Formats.Tabular.TabularRegistry.Handlers[typeof(T)] = handler;"); + writer.Indent--; + writer.WriteLine("}"); + writer.Indent--; + writer.WriteLine("}"); } - private static void BuildHandlerSource(SourceTextBuilder builder, string typeName, in TabularRecordMapping recordMapping) + private static void BuildHandlerSource(SourceTextWriter writer, string typeName, in TabularRecordMapping recordMapping) { - var recordTypeHasHeader = RecordTypeHasHeader(recordMapping); - var recordTypeHasConverters = RecordTypeHasConverters(recordMapping); - - var fieldCountForReading = GetFieldCountForReading(recordMapping); - var fieldCountForWriting = GetFieldCountForWriting(recordMapping); - - var fieldOrders = SortDictionaryKeys(recordMapping.FieldMappings); - - builder.Append("// "); - builder.Append(); - builder.Append("#nullable disable"); - builder.Append(); - builder.Append("namespace Addax.Formats.Tabular.Handlers;"); - builder.Append(); - builder.Append($"[global::System.CodeDom.Compiler.GeneratedCode(\"{s_assemblyInfo.Name}\", \"{s_assemblyInfo.Version}\")]"); - builder.Append($"internal sealed class {typeName} : global::Addax.Formats.Tabular.TabularHandler<{recordMapping.TypeName}>"); - builder.Append("{"); - builder.IndentLevel++; - - if (recordTypeHasHeader) + var recordMappingSupportsHeader = MappingSupportsHeader(recordMapping); + var recordMappingSupportsReading = MappingSupportsReading(recordMapping); + var recordMappingSupportsWriting = MappingSupportsWriting(recordMapping); + var recordMappingHasConverters = MappingHasConverters(recordMapping); + var fieldOrders = GetDictionaryKeysOrdered(recordMapping.FieldMappings); + + writer.WriteLine("// "); + writer.WriteLine(); + writer.WriteLine("#nullable disable"); + writer.WriteLine(); + writer.WriteLine("namespace Addax.Formats.Tabular.Handlers;"); + writer.WriteLine(); + writer.WriteLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"{s_assemblyInfo.Name}\", \"{s_assemblyInfo.Version}\")]"); + writer.WriteLine($"internal sealed class {typeName} : global::Addax.Formats.Tabular.TabularHandler<{recordMapping.TypeName}>"); + writer.WriteLine("{"); + writer.Indent++; + + if (recordMappingSupportsHeader) { - builder.Append("private static readonly global::System.String[] s_header ="); - builder.Append("["); - builder.IndentLevel++; + writer.WriteLine("private static readonly global::System.String[] s_header ="); + writer.WriteLine("["); + writer.Indent++; for (var i = 0; i < fieldOrders.Length; i++) { @@ -71,20 +72,20 @@ private static void BuildHandlerSource(SourceTextBuilder builder, string typeNam if (fieldMapping.FieldNameLiteral.HasValue) { - builder.Append($"{fieldMapping.FieldNameLiteral.Value.Text},"); + writer.WriteLine($"{fieldMapping.FieldNameLiteral.Value.Text},"); } else { - builder.Append("\"\","); + writer.WriteLine("\"\","); } } - builder.IndentLevel--; - builder.Append("];"); - builder.Append(); + writer.Indent--; + writer.WriteLine("];"); + writer.WriteLine(); } - if (recordTypeHasConverters) + if (recordMappingHasConverters) { for (var i = 0; i < fieldOrders.Length; i++) { @@ -93,38 +94,18 @@ private static void BuildHandlerSource(SourceTextBuilder builder, string typeNam if (fieldMapping.ConverterTypeName != null) { - builder.Append($"private readonly {fieldMapping.ConverterTypeName} _converter{fieldOrder} = new();"); + writer.WriteLine($"private readonly {fieldMapping.ConverterTypeName} _c{fieldOrder} = new();"); } } - builder.Append(); + writer.WriteLine(); } - if (fieldCountForReading > 0) + if (recordMappingSupportsReading) { - builder.Append($"public override global::Addax.Formats.Tabular.TabularRecord<{recordMapping.TypeName}> Read(global::Addax.Formats.Tabular.TabularReader reader)"); - builder.Append("{"); - builder.IndentLevel++; - - for (var i = 0; i < fieldOrders.Length; i++) - { - var fieldOrder = fieldOrders[i]; - var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - - if ((fieldMapping.MemberAccess & TypeMemberAccess.Write) != 0) - { - if (!fieldMapping.AsNullableT) - { - builder.Append($"var value{fieldOrder} = default({fieldMapping.ValueTypeName});"); - } - else - { - builder.Append($"var value{fieldOrder} = default({fieldMapping.ValueTypeName}?);"); - } - } - } - - builder.Append(); + writer.WriteLine($"public override global::Addax.Formats.Tabular.TabularRecord<{recordMapping.TypeName}> Read(global::Addax.Formats.Tabular.TabularReader reader)"); + writer.WriteLine("{"); + writer.Indent++; var fieldTypeCheckEmitted = false; @@ -133,7 +114,7 @@ private static void BuildHandlerSource(SourceTextBuilder builder, string typeNam var fieldOrder = fieldOrders[i]; var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - if ((fieldMapping.MemberAccess & TypeMemberAccess.Write) == 0) + if (!fieldMapping.SupportsWriting) { continue; } @@ -142,125 +123,88 @@ private static void BuildHandlerSource(SourceTextBuilder builder, string typeNam if (fieldsToSkip > 0) { - builder.Append($"for (var i = 0; i < {fieldsToSkip}; i++)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("if (!reader.TrySkipField())"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - - if (!fieldTypeCheckEmitted) + for (var j = 0; j < fieldsToSkip; j++) { - builder.Append("if (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - - fieldTypeCheckEmitted = true; + if (fieldTypeCheckEmitted) + { + writer.WriteLine("if (!reader.TrySkipField())"); + } + else + { + writer.WriteLine("if (!reader.TrySkipField() || (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value))"); + + fieldTypeCheckEmitted = true; + } + + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("return default;"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); } - - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); } - builder.Append("if (!reader.TryReadField())"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - - if (!fieldTypeCheckEmitted) + if (fieldTypeCheckEmitted) + { + writer.WriteLine("if (!reader.TryReadField())"); + } + else { - builder.Append("if (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); + writer.WriteLine("if (!reader.TryReadField() || (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value))"); fieldTypeCheckEmitted = true; } + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("return default;"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); + + var defaultValue = !fieldMapping.IsNullableT ? "default" : $"default({fieldMapping.ValueTypeName}?)"; + if (fieldMapping.ConverterTypeName == null) { var valueTypeCode = GetValueTypeCode(fieldMapping.ValueTypeName); - builder.Append($"if (reader.TryGet{valueTypeCode}(out var field{fieldOrder}))"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"value{fieldOrder} = field{fieldOrder};"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"var v{fieldOrder} = reader.TryGet{valueTypeCode}(out var f{fieldOrder}) ? f{fieldOrder} : {defaultValue};"); } else { - builder.Append($"if (reader.TryGet(_converter{fieldOrder}, out var field{fieldOrder}))"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"value{fieldOrder} = field{fieldOrder};"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"var v{fieldOrder} = reader.TryGet(_c{fieldOrder}, out var f{fieldOrder}) ? f{fieldOrder} : {defaultValue};"); } - builder.Append(); - } - - builder.Append($"var record = new {recordMapping.TypeName}"); - builder.Append("{"); - builder.IndentLevel++; - - for (var i = 0; i < fieldOrders.Length; i++) - { - var fieldOrder = fieldOrders[i]; - var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - - if ((fieldMapping.MemberAccess & TypeMemberAccess.Write) != 0) - { - builder.Append($"{fieldMapping.MemberName} = value{fieldOrder},"); - } + writer.WriteLine(); } - builder.IndentLevel--; - builder.Append("};"); - builder.Append(); - builder.Append("return new(record);"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - builder.Append("[global::System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(global::System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<>))]"); - builder.Append($"public override async global::System.Threading.Tasks.ValueTask> ReadAsync(global::Addax.Formats.Tabular.TabularReader reader, global::System.Threading.CancellationToken cancellationToken)"); - builder.Append("{"); - builder.IndentLevel++; + writer.WriteLine($"var r = new {recordMapping.TypeName}"); + writer.WriteLine("{"); + writer.Indent++; for (var i = 0; i < fieldOrders.Length; i++) { var fieldOrder = fieldOrders[i]; var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - if ((fieldMapping.MemberAccess & TypeMemberAccess.Write) != 0) + if (fieldMapping.SupportsWriting) { - if (!fieldMapping.AsNullableT) - { - builder.Append($"var value{fieldOrder} = default({fieldMapping.ValueTypeName});"); - } - else - { - builder.Append($"var value{fieldOrder} = default({fieldMapping.ValueTypeName}?);"); - } + writer.WriteLine($"{fieldMapping.MemberName} = v{fieldOrder},"); } } - builder.Append(); + writer.Indent--; + writer.WriteLine("};"); + writer.WriteLine(); + writer.WriteLine("return new(r);"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine("[global::System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(global::System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<>))]"); + writer.WriteLine($"public override async global::System.Threading.Tasks.ValueTask> ReadAsync(global::Addax.Formats.Tabular.TabularReader reader, global::System.Threading.CancellationToken cancellationToken)"); + writer.WriteLine("{"); + writer.Indent++; fieldTypeCheckEmitted = false; @@ -269,7 +213,7 @@ private static void BuildHandlerSource(SourceTextBuilder builder, string typeNam var fieldOrder = fieldOrders[i]; var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - if ((fieldMapping.MemberAccess & TypeMemberAccess.Write) == 0) + if (!fieldMapping.SupportsWriting) { continue; } @@ -278,269 +222,274 @@ private static void BuildHandlerSource(SourceTextBuilder builder, string typeNam if (fieldsToSkip > 0) { - builder.Append($"for (var i = 0; i < {fieldsToSkip}; i++)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("if (!await reader.TrySkipFieldAsync(cancellationToken).ConfigureAwait(false))"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - - if (!fieldTypeCheckEmitted) + for (var j = 0; j < fieldsToSkip; j++) { - builder.Append("if (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - - fieldTypeCheckEmitted = true; + if (fieldTypeCheckEmitted) + { + writer.WriteLine("if (!await reader.TrySkipFieldAsync(cancellationToken).ConfigureAwait(false))"); + } + else + { + writer.WriteLine("if (!await reader.TrySkipFieldAsync(cancellationToken).ConfigureAwait(false) || (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value))"); + + fieldTypeCheckEmitted = true; + } + + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("return default;"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); } - - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); } - builder.Append("if (!await reader.TryReadFieldAsync(cancellationToken).ConfigureAwait(false))"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - - if (!fieldTypeCheckEmitted) + if (fieldTypeCheckEmitted) + { + writer.WriteLine("if (!await reader.TryReadFieldAsync(cancellationToken).ConfigureAwait(false))"); + } + else { - builder.Append("if (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return default;"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); + writer.WriteLine("if (!await reader.TryReadFieldAsync(cancellationToken).ConfigureAwait(false) || (reader.CurrentFieldType != global::Addax.Formats.Tabular.TabularFieldType.Value))"); fieldTypeCheckEmitted = true; } + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("return default;"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); + + var defaultValue = !fieldMapping.IsNullableT ? "default" : $"default({fieldMapping.ValueTypeName}?)"; + if (fieldMapping.ConverterTypeName == null) { var valueTypeCode = GetValueTypeCode(fieldMapping.ValueTypeName); - builder.Append($"if (reader.TryGet{valueTypeCode}(out var field{fieldOrder}))"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"value{fieldOrder} = field{fieldOrder};"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"var v{fieldOrder} = reader.TryGet{valueTypeCode}(out var f{fieldOrder}) ? f{fieldOrder} : {defaultValue};"); } else { - builder.Append($"if (reader.TryGet(_converter{fieldOrder}, out var field{fieldOrder}))"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"value{fieldOrder} = field{fieldOrder};"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"var v{fieldOrder} = reader.TryGet(_c{fieldOrder}, out var f{fieldOrder}) ? f{fieldOrder} : {defaultValue};"); } - builder.Append(); + writer.WriteLine(); } - builder.Append($"var record = new {recordMapping.TypeName}"); - builder.Append("{"); - builder.IndentLevel++; + writer.WriteLine($"var r = new {recordMapping.TypeName}"); + writer.WriteLine("{"); + writer.Indent++; for (var i = 0; i < fieldOrders.Length; i++) { var fieldOrder = fieldOrders[i]; var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - if ((fieldMapping.MemberAccess & TypeMemberAccess.Write) != 0) + if (fieldMapping.SupportsWriting) { - builder.Append($"{fieldMapping.MemberName} = value{fieldOrder},"); + writer.WriteLine($"{fieldMapping.MemberName} = v{fieldOrder},"); } } - builder.IndentLevel--; - builder.Append("};"); - builder.Append(); - builder.Append("return new(record);"); - builder.IndentLevel--; - builder.Append("}"); + writer.Indent--; + writer.WriteLine("};"); + writer.WriteLine(); + writer.WriteLine("return new(r);"); + writer.Indent--; + writer.WriteLine("}"); } - if (fieldCountForWriting > 0) + if (recordMappingSupportsWriting) { - if (fieldCountForReading > 0) + if (recordMappingSupportsReading) { - builder.Append(); + writer.WriteLine(); } - builder.Append($"public override void Write(global::Addax.Formats.Tabular.TabularWriter writer, {recordMapping.TypeName} record)"); - builder.Append("{"); - builder.IndentLevel++; + writer.WriteLine($"public override void Write(global::Addax.Formats.Tabular.TabularWriter writer, {recordMapping.TypeName} record)"); + writer.WriteLine("{"); + writer.Indent++; for (var i = 0; i < fieldOrders.Length; i++) { var fieldOrder = fieldOrders[i]; var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - if ((fieldMapping.MemberAccess & TypeMemberAccess.Read) == 0) + if (!fieldMapping.SupportsReading) { continue; } + var fieldsToSkip = i > 0 ? fieldOrder - fieldOrders[i - 1] - 1 : fieldOrder; + + if (fieldsToSkip > 0) + { + for (var j = 0; j < fieldsToSkip; j++) + { + writer.WriteLine("writer.WriteEmpty();"); + writer.WriteLine(); + } + } + if (fieldMapping.ConverterTypeName == null) { var valueTypeCode = GetValueTypeCode(fieldMapping.ValueTypeName); - if (fieldMapping.AsNullableT) + if (fieldMapping.IsNullableT) { - builder.Append($"if (record.{fieldMapping.MemberName}.HasValue)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"writer.Write{valueTypeCode}(record.{fieldMapping.MemberName}.Value);"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append("else"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("writer.WriteEmpty();"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"if (record.{fieldMapping.MemberName}.HasValue)"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine($"writer.Write{valueTypeCode}(record.{fieldMapping.MemberName}.Value);"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine("else"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("writer.WriteEmpty();"); + writer.Indent--; + writer.WriteLine("}"); } else { - builder.Append($"writer.Write{valueTypeCode}(record.{fieldMapping.MemberName});"); + writer.WriteLine($"writer.Write{valueTypeCode}(record.{fieldMapping.MemberName});"); } } else { - if (fieldMapping.AsNullableT) + if (fieldMapping.IsNullableT) { - builder.Append($"if (record.{fieldMapping.MemberName}.HasValue)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"writer.Write(record.{fieldMapping.MemberName}.Value, _converter{fieldOrder});"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append("else"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("writer.WriteEmpty();"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"if (record.{fieldMapping.MemberName}.HasValue)"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine($"writer.Write(record.{fieldMapping.MemberName}.Value, _c{fieldOrder});"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine("else"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("writer.WriteEmpty();"); + writer.Indent--; + writer.WriteLine("}"); } else { - builder.Append($"writer.Write(record.{fieldMapping.MemberName}, _converter{fieldOrder});"); + writer.WriteLine($"writer.Write(record.{fieldMapping.MemberName}, _c{fieldOrder});"); } } if (i < recordMapping.FieldMappings.Count - 1) { - builder.Append(); + writer.WriteLine(); } } - builder.IndentLevel--; - builder.Append("}"); - builder.Append(); - builder.Append("[global::System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(global::System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder))]"); - builder.Append($"public override async global::System.Threading.Tasks.ValueTask WriteAsync(global::Addax.Formats.Tabular.TabularWriter writer, {recordMapping.TypeName} record, global::System.Threading.CancellationToken cancellationToken)"); - builder.Append("{"); - builder.IndentLevel++; + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine("[global::System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(global::System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder))]"); + writer.WriteLine($"public override async global::System.Threading.Tasks.ValueTask WriteAsync(global::Addax.Formats.Tabular.TabularWriter writer, {recordMapping.TypeName} record, global::System.Threading.CancellationToken cancellationToken)"); + writer.WriteLine("{"); + writer.Indent++; for (var i = 0; i < fieldOrders.Length; i++) { var fieldOrder = fieldOrders[i]; var fieldMapping = recordMapping.FieldMappings[fieldOrder]; - if ((fieldMapping.MemberAccess & TypeMemberAccess.Read) == 0) + if (!fieldMapping.SupportsReading) { continue; } + var fieldsToSkip = i > 0 ? fieldOrder - fieldOrders[i - 1] - 1 : fieldOrder; + + if (fieldsToSkip > 0) + { + for (var j = 0; j < fieldsToSkip; j++) + { + writer.WriteLine("await writer.WriteEmptyAsync(cancellationToken).ConfigureAwait(false);"); + writer.WriteLine(); + } + } + if (fieldMapping.ConverterTypeName == null) { var valueTypeCode = GetValueTypeCode(fieldMapping.ValueTypeName); - if (fieldMapping.AsNullableT) + if (fieldMapping.IsNullableT) { - builder.Append($"if (record.{fieldMapping.MemberName}.HasValue)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"await writer.Write{valueTypeCode}Async(record.{fieldMapping.MemberName}.Value, cancellationToken).ConfigureAwait(false);"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append("else"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("await writer.WriteEmptyAsync(cancellationToken).ConfigureAwait(false);"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"if (record.{fieldMapping.MemberName}.HasValue)"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine($"await writer.Write{valueTypeCode}Async(record.{fieldMapping.MemberName}.Value, cancellationToken).ConfigureAwait(false);"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine("else"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("await writer.WriteEmptyAsync(cancellationToken).ConfigureAwait(false);"); + writer.Indent--; + writer.WriteLine("}"); } else { - builder.Append($"await writer.Write{valueTypeCode}Async(record.{fieldMapping.MemberName}, cancellationToken).ConfigureAwait(false);"); + writer.WriteLine($"await writer.Write{valueTypeCode}Async(record.{fieldMapping.MemberName}, cancellationToken).ConfigureAwait(false);"); } } else { - if (fieldMapping.AsNullableT) + if (fieldMapping.IsNullableT) { - builder.Append($"if (record.{fieldMapping.MemberName}.HasValue)"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append($"await writer.WriteAsync(record.{fieldMapping.MemberName}.Value, _converter{fieldOrder}, cancellationToken).ConfigureAwait(false);"); - builder.IndentLevel--; - builder.Append("}"); - builder.Append("else"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("await writer.WriteEmptyAsync(cancellationToken).ConfigureAwait(false);"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine($"if (record.{fieldMapping.MemberName}.HasValue)"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine($"await writer.WriteAsync(record.{fieldMapping.MemberName}.Value, _c{fieldOrder}, cancellationToken).ConfigureAwait(false);"); + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine("else"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("await writer.WriteEmptyAsync(cancellationToken).ConfigureAwait(false);"); + writer.Indent--; + writer.WriteLine("}"); } else { - builder.Append($"await writer.WriteAsync(record.{fieldMapping.MemberName}, _converter{fieldOrder}, cancellationToken).ConfigureAwait(false);"); + writer.WriteLine($"await writer.WriteAsync(record.{fieldMapping.MemberName}, _c{fieldOrder}, cancellationToken).ConfigureAwait(false);"); } } if (i < recordMapping.FieldMappings.Count - 1) { - builder.Append(); + writer.WriteLine(); } } - builder.IndentLevel--; - builder.Append("}"); + writer.Indent--; + writer.WriteLine("}"); } - if (recordTypeHasHeader) + if (recordMappingSupportsHeader) { - builder.Append(); - builder.Append("public override global::System.Collections.Generic.IEnumerable Header"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("get"); - builder.Append("{"); - builder.IndentLevel++; - builder.Append("return s_header;"); - builder.IndentLevel--; - builder.Append("}"); - builder.IndentLevel--; - builder.Append("}"); + writer.WriteLine(); + writer.WriteLine("public override global::System.Collections.Generic.IEnumerable Header"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("get"); + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine("return s_header;"); + writer.Indent--; + writer.WriteLine("}"); + writer.Indent--; + writer.WriteLine("}"); } - builder.IndentLevel--; - builder.Append("}"); + writer.Indent--; + writer.WriteLine("}"); } } } diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.cs index 6b29cc4..1db72c2 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.cs +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerEmitter.cs @@ -21,27 +21,28 @@ public void EmitRecordMappings(SourceProductionContext context, ImmutableArray(ImmutableDictionary dictionary) + private static TKey[] GetDictionaryKeysOrdered(ImmutableDictionary dictionary) { var keys = new TKey[dictionary.Count]; var index = 0; @@ -122,12 +111,12 @@ private static TKey[] SortDictionaryKeys(ImmutableDictionary().InformationalVersion; + var assemblyName = assembly.GetName(); + var assemblyVersionAttribute = assembly.GetCustomAttribute(); - return (assemblyName, assemblyVersion); + return (assemblyName.Name, assemblyVersionAttribute.InformationalVersion); } private static string GetValueTypeCode(string valueTypeName) diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerParser.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerParser.cs index 6772b10..dde406d 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerParser.cs +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularHandlerParser.cs @@ -97,7 +97,7 @@ public ImmutableArray GetRecordMappings(CSharpCompilation { cancellationToken.ThrowIfCancellationRequested(); - if (compilation.LanguageVersion < LanguageVersion.CSharp12) + if (compilation.LanguageVersion < LanguageVersion.CSharp13) { context.ReportDiagnostic(Diagnostic.Create(s_diagnostic0000, recordType.Locations.FirstOrDefault())); @@ -224,16 +224,17 @@ public ImmutableArray GetRecordMappings(CSharpCompilation continue; } - var recordMemberAccess = GetTypeMemberAccess(recordMember); + var recordMemberSupportsReading = TypeMemberSupportsReading(recordMember); + var recordMemberSupportsWriting = TypeMemberSupportsWriting(recordMember); if (!recordTypeHasSuitableConstructor || !compilation.IsSymbolAccessibleWithin(recordConstructor, compilation.Assembly)) { - recordMemberAccess &= ~TypeMemberAccess.Write; + recordMemberSupportsWriting = false; + } - if (recordMemberAccess == TypeMemberAccess.None) - { - continue; - } + if (!recordMemberSupportsReading && !recordMemberSupportsWriting) + { + continue; } var fieldNameLiteral = default(SyntaxToken?); @@ -248,7 +249,8 @@ public ImmutableArray GetRecordMappings(CSharpCompilation var fieldMapping = new TabularFieldMapping( recordMember.Name, - recordMemberAccess, + recordMemberSupportsReading, + recordMemberSupportsWriting, valueTypeInfo.IsNullableT, valueTypeInfo.Name, converterTypeName, @@ -421,37 +423,35 @@ private static (ITypeSymbol Type, string Name, bool IsSupported, bool IsNullable return (valueType, valueTypeName, valueTypeIsSupported, memberTypeIsNullableT); } - private static TypeMemberAccess GetTypeMemberAccess(ISymbol member) + private static bool TypeMemberSupportsReading(ISymbol member) { if (member is IFieldSymbol field) { - var memberAccess = TypeMemberAccess.Read; - - if (!field.IsReadOnly && !field.IsConst) - { - memberAccess |= TypeMemberAccess.Write; - } - - return memberAccess; + return true; } else if (member is IPropertySymbol property) { - var memberAccess = TypeMemberAccess.None; - - if (property.GetMethod != null) - { - memberAccess |= TypeMemberAccess.Read; - } - if (property.SetMethod != null) - { - memberAccess |= TypeMemberAccess.Write; - } + return property.GetMethod != null; + } + else + { + return false; + } + } - return memberAccess; + private static bool TypeMemberSupportsWriting(ISymbol member) + { + if (member is IFieldSymbol field) + { + return !field.IsReadOnly && !field.IsConst; + } + else if (member is IPropertySymbol property) + { + return property.SetMethod != null; } else { - return TypeMemberAccess.None; + return false; } } diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularRecordMapping.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularRecordMapping.cs index 53af866..55409b8 100644 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularRecordMapping.cs +++ b/src/Addax.Formats.Tabular.Analyzers.CSharp/TabularRecordMapping.cs @@ -7,12 +7,13 @@ namespace Addax.Formats.Tabular.Analyzers.CSharp { internal readonly struct TabularRecordMapping { - public readonly ImmutableDictionary FieldMappings; public readonly string TypeName; + public readonly ImmutableDictionary FieldMappings; public TabularRecordMapping(string typeName, ImmutableDictionary fieldMappings) { Debug.Assert(typeName != null); + Debug.Assert(fieldMappings != null); TypeName = typeName; FieldMappings = fieldMappings; diff --git a/src/Addax.Formats.Tabular.Analyzers.CSharp/TypeMemberAccess.cs b/src/Addax.Formats.Tabular.Analyzers.CSharp/TypeMemberAccess.cs deleted file mode 100644 index 1fd9f82..0000000 --- a/src/Addax.Formats.Tabular.Analyzers.CSharp/TypeMemberAccess.cs +++ /dev/null @@ -1,14 +0,0 @@ -// (c) Oleksandr Kozlenko. Licensed under the MIT license. - -using System; - -namespace Addax.Formats.Tabular.Analyzers.CSharp -{ - [Flags] - internal enum TypeMemberAccess - { - None = 0, - Read = 1, - Write = 2, - } -} diff --git a/src/Addax.Formats.Tabular.UnitTests/TabularReaderTests.cs b/src/Addax.Formats.Tabular.UnitTests/TabularReaderTests.cs index fdae0d7..49466b5 100644 --- a/src/Addax.Formats.Tabular.UnitTests/TabularReaderTests.cs +++ b/src/Addax.Formats.Tabular.UnitTests/TabularReaderTests.cs @@ -1,4 +1,6 @@ -using System.Text; +#pragma warning disable MSTEST0032 + +using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Addax.Formats.Tabular.UnitTests; diff --git a/src/Addax.Formats.Tabular/Converters/TabularBase16ArrayConverter.cs b/src/Addax.Formats.Tabular/Converters/TabularBase16ArrayConverter.cs index c2716ce..2e019d8 100644 --- a/src/Addax.Formats.Tabular/Converters/TabularBase16ArrayConverter.cs +++ b/src/Addax.Formats.Tabular/Converters/TabularBase16ArrayConverter.cs @@ -5,7 +5,7 @@ namespace Addax.Formats.Tabular.Converters; /// Converts binary data encoded with "base16" ("hex") encoding from or to a character sequence. -public class TabularBase16ArrayConverter : TabularConverter +public class TabularBase16ArrayConverter : TabularConverter { internal static readonly TabularBase16ArrayConverter Instance = new(); diff --git a/src/Addax.Formats.Tabular/Converters/TabularBase64ArrayConverter.cs b/src/Addax.Formats.Tabular/Converters/TabularBase64ArrayConverter.cs index 0a39767..a800508 100644 --- a/src/Addax.Formats.Tabular/Converters/TabularBase64ArrayConverter.cs +++ b/src/Addax.Formats.Tabular/Converters/TabularBase64ArrayConverter.cs @@ -5,7 +5,7 @@ namespace Addax.Formats.Tabular.Converters; /// Converts binary data encoded with "base64" encoding from or to a character sequence. -public class TabularBase64ArrayConverter : TabularConverter +public class TabularBase64ArrayConverter : TabularConverter { internal static readonly TabularBase64ArrayConverter Instance = new(); diff --git a/src/Addax.Formats.Tabular/Converters/TabularUriConverter.cs b/src/Addax.Formats.Tabular/Converters/TabularUriConverter.cs index 98e9ad2..e34faba 100644 --- a/src/Addax.Formats.Tabular/Converters/TabularUriConverter.cs +++ b/src/Addax.Formats.Tabular/Converters/TabularUriConverter.cs @@ -5,7 +5,7 @@ namespace Addax.Formats.Tabular.Converters; /// Converts a instance from or to a character sequence. -public class TabularUriConverter : TabularConverter +public class TabularUriConverter : TabularConverter { internal static readonly TabularUriConverter Instance = new(); diff --git a/src/Addax.Formats.Tabular/Handlers/TabularArrayHandler`1.cs b/src/Addax.Formats.Tabular/Handlers/TabularArrayHandler`1.cs index f5c696d..13b6818 100644 --- a/src/Addax.Formats.Tabular/Handlers/TabularArrayHandler`1.cs +++ b/src/Addax.Formats.Tabular/Handlers/TabularArrayHandler`1.cs @@ -9,12 +9,12 @@ namespace Addax.Formats.Tabular.Handlers; /// The type of field value handled by the record handler. public sealed class TabularArrayHandler : TabularHandler { - private readonly TabularConverter _converter; + private readonly TabularConverter _converter; /// Initializes a new instance of the class with the specified converter. /// The converter to parse and format values with. /// is . - public TabularArrayHandler(TabularConverter converter) + public TabularArrayHandler(TabularConverter converter) { ArgumentNullException.ThrowIfNull(converter); diff --git a/src/Addax.Formats.Tabular/TabularFieldInfo.cs b/src/Addax.Formats.Tabular/Primitives/TabularFieldInfo.cs similarity index 94% rename from src/Addax.Formats.Tabular/TabularFieldInfo.cs rename to src/Addax.Formats.Tabular/Primitives/TabularFieldInfo.cs index 34d88e9..08445ed 100644 --- a/src/Addax.Formats.Tabular/TabularFieldInfo.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularFieldInfo.cs @@ -2,7 +2,7 @@ using System.Diagnostics; -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; internal readonly struct TabularFieldInfo { diff --git a/src/Addax.Formats.Tabular/TabularParserState.cs b/src/Addax.Formats.Tabular/Primitives/TabularParserState.cs similarity index 85% rename from src/Addax.Formats.Tabular/TabularParserState.cs rename to src/Addax.Formats.Tabular/Primitives/TabularParserState.cs index bdb0f4d..a2c0ec4 100644 --- a/src/Addax.Formats.Tabular/TabularParserState.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularParserState.cs @@ -1,6 +1,6 @@ // (c) Oleksandr Kozlenko. Licensed under the MIT license. -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; internal struct TabularParserState { diff --git a/src/Addax.Formats.Tabular/TabularParsingArea.cs b/src/Addax.Formats.Tabular/Primitives/TabularParsingArea.cs similarity index 83% rename from src/Addax.Formats.Tabular/TabularParsingArea.cs rename to src/Addax.Formats.Tabular/Primitives/TabularParsingArea.cs index cb4e14f..2a20ed5 100644 --- a/src/Addax.Formats.Tabular/TabularParsingArea.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularParsingArea.cs @@ -1,6 +1,6 @@ // (c) Oleksandr Kozlenko. Licensed under the MIT license. -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; internal enum TabularParsingArea { diff --git a/src/Addax.Formats.Tabular/TabularParsingMode.cs b/src/Addax.Formats.Tabular/Primitives/TabularParsingMode.cs similarity index 79% rename from src/Addax.Formats.Tabular/TabularParsingMode.cs rename to src/Addax.Formats.Tabular/Primitives/TabularParsingMode.cs index 32fd2e8..526d8e6 100644 --- a/src/Addax.Formats.Tabular/TabularParsingMode.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularParsingMode.cs @@ -1,6 +1,6 @@ // (c) Oleksandr Kozlenko. Licensed under the MIT license. -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; [Flags] internal enum TabularParsingMode diff --git a/src/Addax.Formats.Tabular/TabularSearchValues.cs b/src/Addax.Formats.Tabular/Primitives/TabularSearchValues.cs similarity index 96% rename from src/Addax.Formats.Tabular/TabularSearchValues.cs rename to src/Addax.Formats.Tabular/Primitives/TabularSearchValues.cs index 999fce0..b81eb8c 100644 --- a/src/Addax.Formats.Tabular/TabularSearchValues.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularSearchValues.cs @@ -3,7 +3,7 @@ using System.Buffers; using System.Diagnostics; -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; internal sealed class TabularSearchValues { diff --git a/src/Addax.Formats.Tabular/TabularSeparator.cs b/src/Addax.Formats.Tabular/Primitives/TabularSeparator.cs similarity index 76% rename from src/Addax.Formats.Tabular/TabularSeparator.cs rename to src/Addax.Formats.Tabular/Primitives/TabularSeparator.cs index 8738068..da46658 100644 --- a/src/Addax.Formats.Tabular/TabularSeparator.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularSeparator.cs @@ -1,6 +1,6 @@ // (c) Oleksandr Kozlenko. Licensed under the MIT license. -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; internal enum TabularSeparator { diff --git a/src/Addax.Formats.Tabular/TabularTextInfo.cs b/src/Addax.Formats.Tabular/Primitives/TabularTextInfo.cs similarity index 91% rename from src/Addax.Formats.Tabular/TabularTextInfo.cs rename to src/Addax.Formats.Tabular/Primitives/TabularTextInfo.cs index c594326..258180e 100644 --- a/src/Addax.Formats.Tabular/TabularTextInfo.cs +++ b/src/Addax.Formats.Tabular/Primitives/TabularTextInfo.cs @@ -2,7 +2,7 @@ using System.Diagnostics; -namespace Addax.Formats.Tabular; +namespace Addax.Formats.Tabular.Primitives; internal readonly struct TabularTextInfo { diff --git a/src/Addax.Formats.Tabular/TabularDialect.cs b/src/Addax.Formats.Tabular/TabularDialect.cs index 678b04a..11d65aa 100644 --- a/src/Addax.Formats.Tabular/TabularDialect.cs +++ b/src/Addax.Formats.Tabular/TabularDialect.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Addax.Formats.Tabular.Primitives; namespace Addax.Formats.Tabular; diff --git a/src/Addax.Formats.Tabular/TabularFormatter.cs b/src/Addax.Formats.Tabular/TabularFormatter.cs index 62e5d93..5c31270 100644 --- a/src/Addax.Formats.Tabular/TabularFormatter.cs +++ b/src/Addax.Formats.Tabular/TabularFormatter.cs @@ -2,6 +2,7 @@ using System.Buffers; using System.Diagnostics; +using Addax.Formats.Tabular.Primitives; namespace Addax.Formats.Tabular; diff --git a/src/Addax.Formats.Tabular/TabularParser.cs b/src/Addax.Formats.Tabular/TabularParser.cs index 6d2f123..f56b9a7 100644 --- a/src/Addax.Formats.Tabular/TabularParser.cs +++ b/src/Addax.Formats.Tabular/TabularParser.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using Addax.Formats.Tabular.Buffers; using Addax.Formats.Tabular.Collections; +using Addax.Formats.Tabular.Primitives; namespace Addax.Formats.Tabular; diff --git a/src/Addax.Formats.Tabular/TabularReader.cs b/src/Addax.Formats.Tabular/TabularReader.cs index 9604661..ea0a5ad 100644 --- a/src/Addax.Formats.Tabular/TabularReader.cs +++ b/src/Addax.Formats.Tabular/TabularReader.cs @@ -6,6 +6,7 @@ using Addax.Formats.Tabular.Buffers; using Addax.Formats.Tabular.Collections; using Addax.Formats.Tabular.IO; +using Addax.Formats.Tabular.Primitives; namespace Addax.Formats.Tabular; @@ -256,7 +257,7 @@ public bool TryGetString([NotNullWhen(true)] out string? value) /// When this method returns, contains a value that represents the current field, or an undefined value on failure. This parameter is treated as uninitialized. /// if the field was successfully parsed; otherwise, . /// is . - public bool TryGet(TabularConverter converter, out T? value) + public bool TryGet(TabularConverter converter, out T? value) { ArgumentNullException.ThrowIfNull(converter); @@ -282,7 +283,7 @@ public string GetString() /// A value. /// is . /// The current field cannot be parsed as . - public T? Get(TabularConverter converter) + public T? Get(TabularConverter converter) { ArgumentNullException.ThrowIfNull(converter); @@ -452,7 +453,7 @@ private void ResetCurrentField() _currentFieldCharsUsed = 0; } - private bool TryGet(ReadOnlySpan source, TabularConverter converter, out T? result) + private bool TryGet(ReadOnlySpan source, TabularConverter converter, out T? result) { return converter.TryParse(source, _formatProvider, out result); } diff --git a/src/Addax.Formats.Tabular/TabularRegistry.T.cs b/src/Addax.Formats.Tabular/TabularRegistry.T.cs index 1af2845..da5db87 100644 --- a/src/Addax.Formats.Tabular/TabularRegistry.T.cs +++ b/src/Addax.Formats.Tabular/TabularRegistry.T.cs @@ -60,7 +60,7 @@ private static ConcurrentDictionary CreateHandlers() [typeof(uint?[])] = new TabularSparseArrayHandler(TabularUInt32Converter.Instance), [typeof(ulong[])] = new TabularArrayHandler(TabularUInt64Converter.Instance), [typeof(ulong?[])] = new TabularSparseArrayHandler(TabularUInt64Converter.Instance), - [typeof(Uri?[])] = new TabularArrayHandler(TabularUriConverter.Instance), + [typeof(Uri?[])] = new TabularArrayHandler(TabularUriConverter.Instance), }; } }