Architecture
Mapperly is an incremental .NET source generator implementation. Source generators are explained here and here.
Solution
benchmarksBenchmarks to analyze the performance of the generated code and the source generator itselfbuildBuild scriptsdocsDocumentation of MapperlysamplesSample implementations of Mappers using MapperlysrcSource code of MapperlyRiok.MapperlyThe source generator implementationRiok.Mapperly.AbstractionsAbstractions and attributes to be used by the application code to configure Mapperly. This is referenced by the source generator but is not needed at runtime (except for some features, e.g., reference handling).
testUnit- and integration tests of Mapperly
Flow
This describes the process implemented by Mapperly on a higher level.
For each discovered MapperAttribute a new DescriptorBuilder is created.
The DescriptorBuilder is responsible to build a MapperDescriptor which holds all the mappings.
The DescriptorBuilder does this by following this process:
- Extracting the configuration from the attributes
- Extracting user implemented and user defined mapping methods.
It instantiates a
User*Mapping(eg.UserDefinedNewInstanceMethodMapping) for each discovered mapping method and adds it to the queue of mappings to work on. - Extracting user implemented object factories
- Extracting user implemented format providers
- Extracting external mappings
- For each mapping in the queue the
DescriptorBuildertries to build its implementation bodies. This is done by a so called*MappingBodyBuilder. A mapping body builder tries to map each property from the source to the target. To do this, it asks theDescriptorBuilderto create mappings for the according types. To create a mapping from one type to another, theDescriptorBuilderloops through a set of*MappingBuilders. Each of the mapping builders try to create a mapping (anITypeMappingimplementation) for the asked type mapping by using one approach on how to map types (eg. an explicit cast is implemented by theExplicitCastMappingBuilder). These mappings are queued in the queue of mappings which need the body to be built. - The
SourceEmitteremits the code described by theMapperDescriptorand all its mappings. The syntax objects are created by usingSyntaxFactoryandSyntaxFactoryHelper. TheSyntaxFactoryHelpertries to simplify creating formatted syntax trees. If indentation is needed, theSyntaxFactoryHelperinstance of theSourceEmitterContext/TypeMappingBuildContextcan be used.
Roslyn multi targeting
Mapperly targets multiple Roslyn versions by building multiple NuGet packages and merging them together into a single one. Multi-targeting is needed to support new language features, such as required members introduced in C# 11, while still supporting older compiler versions.
See build/package.sh for details.
To introduce support for a new roslyn version see common tasks.
C# language features
The Mapperly source generator targets .netstandard2.0 but uses the latest C# language version
and polyfills generated by Meziantou.Polyfill.
Some newer C# language features require new runtime features and therefore cannot be used in Mapperly.
A good C# language features requirements overview is available here.