Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primary constructors #922

Merged
merged 1 commit into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions src/Riok.Mapperly/Configuration/AttributeDataAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,11 @@ namespace Riok.Mapperly.Configuration;
/// <summary>
/// Creates <see cref="Attribute"/> instances by resolving attribute data from provided symbols.
/// </summary>
public class AttributeDataAccessor
public class AttributeDataAccessor(SymbolAccessor symbolAccessor)
{
private const string NameOfOperatorName = "nameof";
private const char FullNameOfPrefix = '@';

private readonly SymbolAccessor _symbolAccessor;

public AttributeDataAccessor(SymbolAccessor symbolAccessor)
{
_symbolAccessor = symbolAccessor;
}

public TData AccessSingle<TAttribute, TData>(ISymbol symbol)
where TAttribute : Attribute
where TData : notnull => Access<TAttribute, TData>(symbol).Single();
Expand All @@ -29,7 +22,7 @@ public TData AccessSingle<TAttribute, TData>(ISymbol symbol)
where TData : notnull => Access<TAttribute, TData>(symbol).FirstOrDefault();

public bool HasAttribute<TAttribute>(ISymbol symbol)
where TAttribute : Attribute => _symbolAccessor.HasAttribute<TAttribute>(symbol);
where TAttribute : Attribute => symbolAccessor.HasAttribute<TAttribute>(symbol);

public IEnumerable<TAttribute> Access<TAttribute>(ISymbol symbol)
where TAttribute : Attribute => Access<TAttribute, TAttribute>(symbol);
Expand All @@ -49,7 +42,7 @@ public IEnumerable<TData> Access<TAttribute, TData>(ISymbol symbol)
where TAttribute : Attribute
where TData : notnull
{
var attrDatas = _symbolAccessor.GetAttributes<TAttribute>(symbol);
var attrDatas = symbolAccessor.GetAttributes<TAttribute>(symbol);
foreach (var attrData in attrDatas)
{
yield return Access<TAttribute, TData>(attrData);
Expand Down
9 changes: 2 additions & 7 deletions src/Riok.Mapperly/Configuration/EnumConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,12 @@ namespace Riok.Mapperly.Configuration;
/// Represents the <see cref="MapEnumAttribute"/>
/// with enum values as typed constants.
/// </summary>
public class EnumConfiguration
public class EnumConfiguration(EnumMappingStrategy strategy)
{
public EnumConfiguration(EnumMappingStrategy strategy)
{
Strategy = strategy;
}

/// <summary>
/// The strategy to be used to map enums.
/// </summary>
public EnumMappingStrategy Strategy { get; }
public EnumMappingStrategy Strategy { get; } = strategy;

/// <summary>
/// Whether the case should be ignored during mappings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,15 @@ namespace Riok.Mapperly.Descriptors.Enumerables.EnsureCapacity;
/// target.EnsureCapacity(source.Length + target.Count);
/// </code>
/// </remarks>
public class EnsureCapacityMember : EnsureCapacityInfo
public class EnsureCapacityMember(string targetAccessor, string sourceAccessor) : EnsureCapacityInfo
{
private readonly string _targetAccessor;
private readonly string _sourceAccessor;

public EnsureCapacityMember(string targetAccessor, string sourceAccessor)
{
_targetAccessor = targetAccessor;
_sourceAccessor = sourceAccessor;
}

public override StatementSyntax Build(TypeMappingBuildContext ctx, ExpressionSyntax target)
{
return EnsureCapacityStatement(
ctx.SyntaxFactory,
target,
MemberAccess(ctx.Source, _sourceAccessor),
MemberAccess(target, _targetAccessor)
MemberAccess(ctx.Source, sourceAccessor),
MemberAccess(target, targetAccessor)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,13 @@ namespace Riok.Mapperly.Descriptors.Enumerables.EnsureCapacity;
/// target.EnsureCapacity(sourceCount + target.Count);
/// </code>
/// </remarks>
public class EnsureCapacityNonEnumerated : EnsureCapacityInfo
public class EnsureCapacityNonEnumerated(string targetAccessor, IMethodSymbol getNonEnumeratedMethod) : EnsureCapacityInfo
{
private const string SourceCountVariableName = "sourceCount";
private readonly string _targetAccessor;
private readonly IMethodSymbol _getNonEnumeratedMethod;

public EnsureCapacityNonEnumerated(string targetAccessor, IMethodSymbol getNonEnumeratedMethod)
{
_targetAccessor = targetAccessor;
_getNonEnumeratedMethod = getNonEnumeratedMethod;
}

public override StatementSyntax Build(TypeMappingBuildContext ctx, ExpressionSyntax target)
{
var targetCount = MemberAccess(target, _targetAccessor);
var targetCount = MemberAccess(target, targetAccessor);

var countIdentifier = Identifier(ctx.NameBuilder.New(SourceCountVariableName));
var countIdentifierName = IdentifierName(countIdentifier);
Expand All @@ -42,7 +34,7 @@ public override StatementSyntax Build(TypeMappingBuildContext ctx, ExpressionSyn
var outVarArgument = Argument(DeclarationExpression(VarIdentifier, SingleVariableDesignation(countIdentifier)))
.WithRefOrOutKeyword(TrailingSpacedToken(SyntaxKind.OutKeyword));

var getNonEnumeratedInvocation = StaticInvocation(_getNonEnumeratedMethod, enumerableArgument, outVarArgument);
var getNonEnumeratedInvocation = StaticInvocation(getNonEnumeratedMethod, enumerableArgument, outVarArgument);
var ensureCapacity = EnsureCapacityStatement(ctx.SyntaxFactory.AddIndentation(), target, countIdentifierName, targetCount);
return ctx.SyntaxFactory.If(getNonEnumeratedInvocation, ensureCapacity);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
/// An <see cref="IMembersContainerBuilderContext{T}"/> implementation.
/// </summary>
/// <typeparam name="T">The type of mapping.</typeparam>
public class MembersContainerBuilderContext<T> : MembersMappingBuilderContext<T>, IMembersContainerBuilderContext<T>
public class MembersContainerBuilderContext<T>(MappingBuilderContext builderContext, T mapping)
: MembersMappingBuilderContext<T>(builderContext, mapping),
IMembersContainerBuilderContext<T>
where T : IMemberAssignmentTypeMapping
{
private readonly Dictionary<MemberPath, MemberNullDelegateAssignmentMapping> _nullDelegateMappings = new();

public MembersContainerBuilderContext(MappingBuilderContext builderContext, T mapping)
: base(builderContext, mapping) { }

public void AddMemberAssignmentMapping(IMemberAssignmentMapping memberMapping) => AddMemberAssignmentMapping(Mapping, memberMapping);

public void AddNullDelegateMemberAssignmentMapping(IMemberAssignmentMapping memberMapping)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
/// An implementation of <see cref="INewInstanceBuilderContext{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the mapping.</typeparam>
public class NewInstanceBuilderContext<T> : MembersMappingBuilderContext<T>, INewInstanceBuilderContext<T>
public class NewInstanceBuilderContext<T>(MappingBuilderContext builderContext, T mapping)
: MembersMappingBuilderContext<T>(builderContext, mapping),
INewInstanceBuilderContext<T>
where T : INewInstanceObjectMemberMapping
{
public NewInstanceBuilderContext(MappingBuilderContext builderContext, T mapping)
: base(builderContext, mapping) { }

public void AddInitMemberMapping(MemberAssignmentMapping mapping)
{
SetSourceMemberMapped(mapping.SourcePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
/// which supports containers (<seealso cref="MembersContainerBuilderContext{T}"/>).
/// </summary>
/// <typeparam name="T"></typeparam>
public class NewInstanceContainerBuilderContext<T> : MembersContainerBuilderContext<T>, INewInstanceBuilderContext<T>
public class NewInstanceContainerBuilderContext<T>(MappingBuilderContext builderContext, T mapping)
: MembersContainerBuilderContext<T>(builderContext, mapping),
INewInstanceBuilderContext<T>
where T : INewInstanceObjectMemberMapping, IMemberAssignmentTypeMapping
{
public NewInstanceContainerBuilderContext(MappingBuilderContext builderContext, T mapping)
: base(builderContext, mapping) { }

public void AddInitMemberMapping(MemberAssignmentMapping mapping)
{
SetSourceMemberMapped(mapping.SourcePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
/// An implementation of <see cref="INewValueTupleBuilderContext{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the mapping.</typeparam>
public class NewValueTupleConstructorBuilderContext<T> : MembersMappingBuilderContext<T>, INewValueTupleBuilderContext<T>
public class NewValueTupleConstructorBuilderContext<T>(MappingBuilderContext builderContext, T mapping)
: MembersMappingBuilderContext<T>(builderContext, mapping),
INewValueTupleBuilderContext<T>
where T : INewValueTupleMapping
{
public NewValueTupleConstructorBuilderContext(MappingBuilderContext builderContext, T mapping)
: base(builderContext, mapping) { }

public void AddTupleConstructorParameterMapping(ValueTupleConstructorParameterMapping mapping)
{
MemberConfigsByRootTargetName.Remove(mapping.Parameter.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
/// An implementation of <see cref="INewValueTupleBuilderContext{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the mapping.</typeparam>
public class NewValueTupleExpressionBuilderContext<T> : MembersContainerBuilderContext<T>, INewValueTupleBuilderContext<T>
public class NewValueTupleExpressionBuilderContext<T>(MappingBuilderContext builderContext, T mapping)
: MembersContainerBuilderContext<T>(builderContext, mapping),
INewValueTupleBuilderContext<T>
where T : INewValueTupleMapping, IMemberAssignmentTypeMapping
{
public NewValueTupleExpressionBuilderContext(MappingBuilderContext builderContext, T mapping)
: base(builderContext, mapping) { }

public void AddTupleConstructorParameterMapping(ValueTupleConstructorParameterMapping mapping)
{
if (MemberConfigsByRootTargetName.TryGetValue(mapping.Parameter.Name, out var value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,11 @@ namespace Riok.Mapperly.Descriptors.MappingBodyBuilders;
/// <summary>
/// Builds bodies mappings (the body of the mapping methods).
/// </summary>
public class MappingBodyBuilder
public class MappingBodyBuilder(MappingCollection mappings)
{
private readonly MappingCollection _mappings;

public MappingBodyBuilder(MappingCollection mappings)
{
_mappings = mappings;
}

public void BuildMappingBodies(CancellationToken cancellationToken)
{
foreach (var (typeMapping, ctx) in _mappings.DequeueMappingsToBuildBody())
foreach (var (typeMapping, ctx) in mappings.DequeueMappingsToBuildBody())
{
cancellationToken.ThrowIfCancellationRequested();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Riok.Mapperly.Descriptors.MappingBuilders;

public class ExistingTargetMappingBuilder
public class ExistingTargetMappingBuilder(MappingCollection mappings)
{
private delegate IExistingTargetMapping? BuildExistingTargetMapping(MappingBuilderContext context);

Expand All @@ -16,16 +16,9 @@ public class ExistingTargetMappingBuilder
NewInstanceObjectPropertyMappingBuilder.TryBuildExistingTargetMapping,
};

private readonly MappingCollection _mappings;

public ExistingTargetMappingBuilder(MappingCollection mappings)
{
_mappings = mappings;
}

public IExistingTargetMapping? Find(TypeMappingKey mappingKey)
{
return _mappings.FindExistingInstanceMapping(mappingKey);
return mappings.FindExistingInstanceMapping(mappingKey);
}

public IExistingTargetMapping? Build(MappingBuilderContext ctx, bool resultIsReusable)
Expand All @@ -37,10 +30,10 @@ public ExistingTargetMappingBuilder(MappingCollection mappings)

if (resultIsReusable)
{
_mappings.AddExistingTargetMapping(mapping, ctx.MappingKey.Configuration);
mappings.AddExistingTargetMapping(mapping, ctx.MappingKey.Configuration);
}

_mappings.EnqueueToBuildBody(mapping, ctx);
mappings.EnqueueToBuildBody(mapping, ctx);
return mapping;
}

Expand Down
17 changes: 5 additions & 12 deletions src/Riok.Mapperly/Descriptors/MappingBuilders/MappingBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Riok.Mapperly.Descriptors.MappingBuilders;

public class MappingBuilder
public class MappingBuilder(MappingCollection mappings)
{
private delegate INewInstanceMapping? BuildMapping(MappingBuilderContext context);

Expand Down Expand Up @@ -31,17 +31,10 @@ public class MappingBuilder
NewInstanceObjectPropertyMappingBuilder.TryBuildMapping,
};

private readonly MappingCollection _mappings;

public MappingBuilder(MappingCollection mappings)
{
_mappings = mappings;
}

/// <inheritdoc cref="MappingCollection.UserMappings"/>
public IReadOnlyCollection<IUserMapping> UserMappings => _mappings.UserMappings;
public IReadOnlyCollection<IUserMapping> UserMappings => mappings.UserMappings;

public INewInstanceMapping? Find(TypeMappingKey mapping) => _mappings.Find(mapping);
public INewInstanceMapping? Find(TypeMappingKey mapping) => mappings.Find(mapping);

public INewInstanceMapping? Build(MappingBuilderContext ctx, bool resultIsReusable)
{
Expand All @@ -52,10 +45,10 @@ public MappingBuilder(MappingCollection mappings)

if (resultIsReusable)
{
_mappings.AddNewInstanceMapping(mapping, ctx.MappingKey.Configuration);
mappings.AddNewInstanceMapping(mapping, ctx.MappingKey.Configuration);
}

_mappings.EnqueueToBuildBody(mapping, ctx);
mappings.EnqueueToBuildBody(mapping, ctx);
return mapping;
}

Expand Down
5 changes: 1 addition & 4 deletions src/Riok.Mapperly/Descriptors/Mappings/ArrayCloneMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@ namespace Riok.Mapperly.Descriptors.Mappings;
/// <summary>
/// Represents a mapping from an array to an array of the same type by using Array.Clone.
/// </summary>
public class ArrayCloneMapping : NewInstanceMapping
public class ArrayCloneMapping(ITypeSymbol sourceType, ITypeSymbol targetType) : NewInstanceMapping(sourceType, targetType)
{
private const string CloneMethodName = nameof(Array.Clone);

public ArrayCloneMapping(ITypeSymbol sourceType, ITypeSymbol targetType)
: base(sourceType, targetType) { }

public override ExpressionSyntax Build(TypeMappingBuildContext ctx)
{
return CastExpression(FullyQualifiedIdentifier(TargetType), InvocationExpression(MemberAccess(ctx.Source, CloneMethodName)));
Expand Down
32 changes: 10 additions & 22 deletions src/Riok.Mapperly/Descriptors/Mappings/ArrayForEachMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,29 @@ namespace Riok.Mapperly.Descriptors.Mappings;
/// Represents an enumerable to array mapping which works by initialising an array, looping through the source,
/// mapping each element and adding it to the target array.
/// </summary>
public class ArrayForEachMapping : MethodMapping
public class ArrayForEachMapping(
ITypeSymbol sourceType,
ITypeSymbol targetType,
INewInstanceMapping elementMapping,
ITypeSymbol targetArrayElementType,
string countPropertyName
) : MethodMapping(sourceType, targetType)
{
private const string TargetVariableName = "target";
private const string LoopItemVariableName = "item";
private const string LoopCounterName = "i";

private readonly INewInstanceMapping _elementMapping;
private readonly ITypeSymbol _targetArrayElementType;
private readonly string _countPropertyName;

public ArrayForEachMapping(
ITypeSymbol sourceType,
ITypeSymbol targetType,
INewInstanceMapping elementMapping,
ITypeSymbol targetArrayElementType,
string countPropertyName
)
: base(sourceType, targetType)
{
_elementMapping = elementMapping;
_targetArrayElementType = targetArrayElementType;
_countPropertyName = countPropertyName;
}

public override IEnumerable<StatementSyntax> BuildBody(TypeMappingBuildContext ctx)
{
var targetVariableName = ctx.NameBuilder.New(TargetVariableName);
var loopCounterVariableName = ctx.NameBuilder.New(LoopCounterName);

// var target = new T[source.Count];
var sourceLengthArrayRank = ArrayRankSpecifier(
SingletonSeparatedList<ExpressionSyntax>(MemberAccess(ctx.Source, _countPropertyName))
SingletonSeparatedList<ExpressionSyntax>(MemberAccess(ctx.Source, countPropertyName))
);
var targetInitializationValue = CreateArray(
ArrayType(FullyQualifiedIdentifier(_targetArrayElementType)).WithRankSpecifiers(SingletonList(sourceLengthArrayRank))
ArrayType(FullyQualifiedIdentifier(targetArrayElementType)).WithRankSpecifiers(SingletonList(sourceLengthArrayRank))
);
yield return ctx.SyntaxFactory.DeclareLocalVariable(targetVariableName, targetInitializationValue);

Expand All @@ -53,7 +41,7 @@ public override IEnumerable<StatementSyntax> BuildBody(TypeMappingBuildContext c

// target[i] = Map(item);
var (loopItemCtx, loopItemVariableName) = ctx.WithNewSource(LoopItemVariableName);
var convertedSourceItemExpression = _elementMapping.Build(loopItemCtx.AddIndentation());
var convertedSourceItemExpression = elementMapping.Build(loopItemCtx.AddIndentation());

var assignment = Assignment(
ElementAccess(IdentifierName(targetVariableName), IdentifierName(loopCounterVariableName)),
Expand Down
Loading