diff --git a/src/MapTo/MapToGenerator.cs b/src/MapTo/MapToGenerator.cs
index 1e5f581..d740394 100644
--- a/src/MapTo/MapToGenerator.cs
+++ b/src/MapTo/MapToGenerator.cs
@@ -61,6 +61,7 @@ namespace MapTo
var (source, hintName) = typeDeclarationSyntax switch
{
+ StructDeclarationSyntax => MapStructSource.Generate(mappingContext.Model),
ClassDeclarationSyntax => MapClassSource.Generate(mappingContext.Model),
RecordDeclarationSyntax => MapRecordSource.Generate(mappingContext.Model),
_ => throw new ArgumentOutOfRangeException()
diff --git a/src/MapTo/Sources/MapStructSource.cs b/src/MapTo/Sources/MapStructSource.cs
new file mode 100644
index 0000000..6177468
--- /dev/null
+++ b/src/MapTo/Sources/MapStructSource.cs
@@ -0,0 +1,172 @@
+using MapTo.Extensions;
+using static MapTo.Sources.Constants;
+
+namespace MapTo.Sources
+{
+ internal static class MapStructSource
+ {
+ internal static SourceCode Generate(MappingModel model)
+ {
+ using var builder = new SourceBuilder()
+ .WriteLine(GeneratedFilesHeader)
+ .WriteNullableContextOptionIf(model.Options.SupportNullableReferenceTypes)
+ .WriteUsings(model.Usings)
+ .WriteLine()
+
+ // Namespace declaration
+ .WriteLine($"namespace {model.Namespace}")
+ .WriteOpeningBracket()
+
+ // Class declaration
+ .WriteLine($"partial class {model.TypeIdentifierName}")
+ .WriteOpeningBracket();
+
+ // Class body
+ if (model.GenerateSecondaryConstructor)
+ {
+ builder
+ .GenerateSecondaryConstructor(model)
+ .WriteLine();
+ }
+
+ builder
+ .GeneratePrivateConstructor(model)
+ .WriteLine()
+ // End class declaration
+ .WriteClosingBracket()
+ .WriteLine()
+
+ // End namespace declaration
+ .WriteClosingBracket();
+
+ return new(builder.ToString(), $"{model.Namespace}.{model.TypeIdentifierName}.g.cs");
+ }
+
+ private static SourceBuilder GenerateSecondaryConstructor(this SourceBuilder builder, MappingModel model)
+ {
+ var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
+
+ if (model.Options.GenerateXmlDocument)
+ {
+ builder
+ .WriteLine("/// ")
+ .WriteLine($"/// Initializes a new instance of the class")
+ .WriteLine($"/// using the property values from the specified .")
+ .WriteLine("/// ")
+ .WriteLine($"/// {sourceClassParameterName} is null");
+ }
+
+ return builder
+ .WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.TypeIdentifierName}({model.SourceType} {sourceClassParameterName})")
+ .WriteLine($" : this(new {MappingContextSource.ClassName}(), {sourceClassParameterName}) {{ }}");
+ }
+
+ private static SourceBuilder GeneratePrivateConstructor(this SourceBuilder builder, MappingModel model)
+ {
+ var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
+ const string mappingContextParameterName = "context";
+
+ var baseConstructor = model.HasMappedBaseClass ? $" : base({mappingContextParameterName}, {sourceClassParameterName})" : string.Empty;
+
+ builder
+ .WriteLine($"private protected {model.TypeIdentifierName}({MappingContextSource.ClassName} {mappingContextParameterName}, {model.SourceType} {sourceClassParameterName}){baseConstructor}")
+ .WriteOpeningBracket()
+ .WriteLine()
+ .WriteLine($"{mappingContextParameterName}.{MappingContextSource.RegisterMethodName}({sourceClassParameterName}, this);")
+ .WriteLine().
+
+ WriteProperties( model, sourceClassParameterName, mappingContextParameterName);
+
+ // End constructor declaration
+ return builder.WriteClosingBracket();
+ }
+
+ private static SourceBuilder WriteProperties(this SourceBuilder builder, MappingModel model,
+ string? sourceClassParameterName, string mappingContextParameterName)
+ {
+ foreach (var property in model.MappedProperties)
+ {
+ if (property.TypeConverter is null)
+ {
+ if (property.IsEnumerable)
+ {
+ builder.WriteLine(
+ $"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName}.Select({mappingContextParameterName}.{MappingContextSource.MapMethodName}<{property.MappedSourcePropertyTypeName}, {property.EnumerableTypeArgument}>).ToList();");
+ }
+ else
+ {
+ builder.WriteLine(property.MappedSourcePropertyTypeName is null
+ ? $"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};"
+ : $"{property.Name} = {mappingContextParameterName}.{MappingContextSource.MapMethodName}<{property.MappedSourcePropertyTypeName}, {property.Type}>({sourceClassParameterName}.{property.SourcePropertyName});");
+ }
+ }
+ else
+ {
+ var parameters = property.TypeConverterParameters.IsEmpty
+ ? "null"
+ : $"new object[] {{ {string.Join(", ", property.TypeConverterParameters)} }}";
+
+ builder.WriteLine(
+ $"{property.Name} = new {property.TypeConverter}().Convert({sourceClassParameterName}.{property.SourcePropertyName}, {parameters});");
+ }
+
+ }
+ return builder;
+
+ }
+
+
+ private static SourceBuilder GenerateConvertorMethodsXmlDocs(this SourceBuilder builder, MappingModel model, string sourceClassParameterName)
+ {
+ if (!model.Options.GenerateXmlDocument)
+ {
+ return builder;
+ }
+
+ return builder
+ .WriteLine("/// ")
+ .WriteLine($"/// Creates a new instance of and sets its participating properties")
+ .WriteLine($"/// using the property values from .")
+ .WriteLine("/// ")
+ .WriteLine($"/// The instance of to use as source.")
+ .WriteLine($"/// A new instance of -or- null if is null.");
+ }
+
+ private static SourceBuilder GenerateUpdaterMethodsXmlDocs(this SourceBuilder builder, MappingModel model, string sourceClassParameterName)
+ {
+ if (!model.Options.GenerateXmlDocument)
+ {
+ return builder;
+ }
+
+ return builder
+ .WriteLine("/// ")
+ .WriteLine($"/// Updates and sets its participating properties")
+ .WriteLine($"/// using the property values from .")
+ .WriteLine("/// ")
+ .WriteLine($"/// The instance of to use as source.");
+ }
+
+ private static SourceBuilder GenerateSourceTypeExtensionClass(this SourceBuilder builder, MappingModel model)
+ {
+ return builder
+ .WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static partial class {model.SourceTypeIdentifierName}To{model.TypeIdentifierName}Extensions")
+ .WriteOpeningBracket()
+ .GenerateSourceTypeExtensionMethod(model)
+ .WriteClosingBracket();
+ }
+
+ private static SourceBuilder GenerateSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model)
+ {
+ var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
+
+ return builder
+ .GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
+ .WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
+ .WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} To{model.TypeIdentifierName}(this {model.SourceType}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
+ .WriteOpeningBracket()
+ .WriteLine($"return {sourceClassParameterName} == null ? null : new {model.TypeIdentifierName}({sourceClassParameterName});")
+ .WriteClosingBracket();
+ }
+ }
+}
\ No newline at end of file