-
-
Notifications
You must be signed in to change notification settings - Fork 127
/
EnumMappingBuilder.cs
72 lines (62 loc) · 2.86 KB
/
EnumMappingBuilder.cs
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
using Microsoft.CodeAnalysis;
using Riok.Mapperly.Abstractions;
using Riok.Mapperly.Descriptors.Mappings;
using Riok.Mapperly.Diagnostics;
using Riok.Mapperly.Helpers;
namespace Riok.Mapperly.Descriptors.MappingBuilder;
public static class EnumMappingBuilder
{
public static TypeMapping? TryBuildMapping(MappingBuilderContext ctx)
{
var sourceIsEnum = ctx.Source.TryGetEnumUnderlyingType(out var sourceEnumType);
var targetIsEnum = ctx.Target.TryGetEnumUnderlyingType(out var targetEnumType);
// none is an enum
if (!sourceIsEnum && !targetIsEnum)
return null;
// one is an enum, other may be an underlying type (eg. int)
if (!sourceIsEnum || !targetIsEnum)
{
return ctx.FindOrBuildMapping(sourceEnumType ?? ctx.Source, targetEnumType ?? ctx.Target) is { } delegateMapping
? new CastMapping(ctx.Source, ctx.Target, delegateMapping)
: null;
}
// since enums are immutable they can be directly assigned if they are of the same type
if (SymbolEqualityComparer.IncludeNullability.Equals(ctx.Source, ctx.Target))
return new DirectAssignmentMapping(ctx.Source);
// map enums by strategy
var config = ctx.GetConfigurationOrDefault<MapEnumAttribute>();
return config.Strategy switch
{
EnumMappingStrategy.ByName => BuildNameMapping(ctx, config.IgnoreCase),
_ => new CastMapping(ctx.Source, ctx.Target),
};
}
private static TypeMapping BuildNameMapping(MappingBuilderContext ctx, bool ignoreCase)
{
var targetFieldsByName = ctx.Target.GetMembers().OfType<IFieldSymbol>().ToDictionary(x => x.Name);
Func<IFieldSymbol, IFieldSymbol?> getTargetField;
if (ignoreCase)
{
var targetFieldsByNameIgnoreCase = targetFieldsByName
.DistinctBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
getTargetField = source => targetFieldsByName.GetValueOrDefault(source.Name) ?? targetFieldsByNameIgnoreCase.GetValueOrDefault(source.Name);
}
else
{
getTargetField = source => targetFieldsByName.GetValueOrDefault(source.Name);
}
var enumMemberMappings = ctx.Source.GetMembers().OfType<IFieldSymbol>()
.Select(x => (Source: x, Target: getTargetField(x)))
.Where(x => x.Target != null)
.ToDictionary(x => x.Source.Name, x => x.Target!.Name);
if (enumMemberMappings.Count == 0)
{
ctx.ReportDiagnostic(
DiagnosticDescriptors.EnumNameMappingNoOverlappingValuesFound,
ctx.Source,
ctx.Target);
}
return new EnumNameMapping(ctx.Source, ctx.Target, enumMemberMappings);
}
}