From 7acb1b841258e4abc9cf3ccdf6f26d4b184c711d Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Bastida Date: Sat, 3 Jan 2026 09:05:43 +0100 Subject: [PATCH 1/5] Upgrade to .NET 10 --- Funzo.Example/Funzo.Example.csproj | 3 ++- Funzo.Generator/Funzo.Generator.csproj | 2 +- Funzo.Serialization/Funzo.Serialization.csproj | 4 ++-- .../Funzo.SourceGenerators.Test.csproj | 8 ++++---- Funzo.SourceGenerators/Funzo.SourceGenerators.csproj | 4 ++-- Funzo.Test/Funzo.Test.csproj | 6 +++--- Funzo/Funzo.csproj | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Funzo.Example/Funzo.Example.csproj b/Funzo.Example/Funzo.Example.csproj index 168d3c6..1bf4d04 100644 --- a/Funzo.Example/Funzo.Example.csproj +++ b/Funzo.Example/Funzo.Example.csproj @@ -2,8 +2,9 @@ Exe - net9.0 + net10 enable + latest enable diff --git a/Funzo.Generator/Funzo.Generator.csproj b/Funzo.Generator/Funzo.Generator.csproj index 6edc84f..48fcde8 100644 --- a/Funzo.Generator/Funzo.Generator.csproj +++ b/Funzo.Generator/Funzo.Generator.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10 enable enable false diff --git a/Funzo.Serialization/Funzo.Serialization.csproj b/Funzo.Serialization/Funzo.Serialization.csproj index 3be36f8..d1edf95 100644 --- a/Funzo.Serialization/Funzo.Serialization.csproj +++ b/Funzo.Serialization/Funzo.Serialization.csproj @@ -1,7 +1,7 @@  - net9.0;netstandard2.1;netstandard2.0 + net10 enable latest enable @@ -31,7 +31,7 @@ - + diff --git a/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj b/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj index 62e570e..bce22c7 100644 --- a/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj +++ b/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj @@ -1,7 +1,7 @@  - net9.0;net481;net5.0 + net10 disable enable latest @@ -10,10 +10,10 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj b/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj index c03d77b..a685745 100644 --- a/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj +++ b/Funzo.SourceGenerators/Funzo.SourceGenerators.csproj @@ -36,11 +36,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/Funzo.Test/Funzo.Test.csproj b/Funzo.Test/Funzo.Test.csproj index fff52a4..548760c 100644 --- a/Funzo.Test/Funzo.Test.csproj +++ b/Funzo.Test/Funzo.Test.csproj @@ -1,6 +1,6 @@ - net9.0;net481;net5.0 + net10 disable enable true @@ -10,9 +10,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Funzo/Funzo.csproj b/Funzo/Funzo.csproj index aca61b5..7c4e1f9 100644 --- a/Funzo/Funzo.csproj +++ b/Funzo/Funzo.csproj @@ -1,7 +1,7 @@  - net9.0;netstandard2.1;netstandard2.0 + net10 enable 11.0 enable From 771090481161a047606c8b2f36fd1279a7548dd9 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Bastida Date: Sat, 3 Jan 2026 09:07:34 +0100 Subject: [PATCH 2/5] Fix naming Add lang latest version to main project --- Funzo.Example/Funzo.Example.csproj | 2 +- Funzo.Generator/Funzo.Generator.csproj | 2 +- Funzo.Serialization/Funzo.Serialization.csproj | 2 +- .../Funzo.SourceGenerators.Test.csproj | 2 +- Funzo.Test/Funzo.Test.csproj | 4 ++-- Funzo/Funzo.csproj | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Funzo.Example/Funzo.Example.csproj b/Funzo.Example/Funzo.Example.csproj index 1bf4d04..05e1890 100644 --- a/Funzo.Example/Funzo.Example.csproj +++ b/Funzo.Example/Funzo.Example.csproj @@ -2,7 +2,7 @@ Exe - net10 + net10.0 enable latest enable diff --git a/Funzo.Generator/Funzo.Generator.csproj b/Funzo.Generator/Funzo.Generator.csproj index 48fcde8..8f53460 100644 --- a/Funzo.Generator/Funzo.Generator.csproj +++ b/Funzo.Generator/Funzo.Generator.csproj @@ -2,7 +2,7 @@ Exe - net10 + net10.0 enable enable false diff --git a/Funzo.Serialization/Funzo.Serialization.csproj b/Funzo.Serialization/Funzo.Serialization.csproj index d1edf95..b76faca 100644 --- a/Funzo.Serialization/Funzo.Serialization.csproj +++ b/Funzo.Serialization/Funzo.Serialization.csproj @@ -1,7 +1,7 @@  - net10 + net10.0 enable latest enable diff --git a/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj b/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj index bce22c7..b216c91 100644 --- a/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj +++ b/Funzo.SourceGenerators.Test/Funzo.SourceGenerators.Test.csproj @@ -1,7 +1,7 @@  - net10 + net10.0 disable enable latest diff --git a/Funzo.Test/Funzo.Test.csproj b/Funzo.Test/Funzo.Test.csproj index 548760c..8f463c4 100644 --- a/Funzo.Test/Funzo.Test.csproj +++ b/Funzo.Test/Funzo.Test.csproj @@ -1,6 +1,6 @@ - + - net10 + net10.0 disable enable true diff --git a/Funzo/Funzo.csproj b/Funzo/Funzo.csproj index 7c4e1f9..e1684d1 100644 --- a/Funzo/Funzo.csproj +++ b/Funzo/Funzo.csproj @@ -1,9 +1,9 @@  - net10 + net10.0 enable - 11.0 + latest enable true Funzo From dc863dc0f62c3f4b5e2144f6259209b8903030e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez?= Date: Sat, 3 Jan 2026 09:10:18 +0100 Subject: [PATCH 3/5] Rename ResultBuilderTEsts.cs to ResultBuilderTests.cs --- .../{ResultBuilderTEsts.cs => ResultBuilderTests.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Funzo.SourceGenerators.Test/{ResultBuilderTEsts.cs => ResultBuilderTests.cs} (99%) diff --git a/Funzo.SourceGenerators.Test/ResultBuilderTEsts.cs b/Funzo.SourceGenerators.Test/ResultBuilderTests.cs similarity index 99% rename from Funzo.SourceGenerators.Test/ResultBuilderTEsts.cs rename to Funzo.SourceGenerators.Test/ResultBuilderTests.cs index 11c79c2..040c932 100644 --- a/Funzo.SourceGenerators.Test/ResultBuilderTEsts.cs +++ b/Funzo.SourceGenerators.Test/ResultBuilderTests.cs @@ -126,4 +126,4 @@ public partial class MyError ; public class ArgumentError; public class InvalidError; -public class UnknownError; \ No newline at end of file +public class UnknownError; From d64d079ca3f8da0eb16be4112ec66d028dba6a0d Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Bastida Date: Sat, 3 Jan 2026 10:03:16 +0100 Subject: [PATCH 4/5] Allow definition inside partial classes --- .../ResultGeneratorTests.cs | 19 +- .../UnionGeneratorTests.cs | 19 + .../Generators/ResultSourceGenerator.cs | 37 +- .../Generators/Unions/UnionSourceGenerator.cs | 27 +- .../Helpers/FunzoDiagnosticDescriptors.cs | 5 +- Funzo/Union.generated.cs | 720 +++++++++--------- 6 files changed, 453 insertions(+), 374 deletions(-) diff --git a/Funzo.SourceGenerators.Test/ResultGeneratorTests.cs b/Funzo.SourceGenerators.Test/ResultGeneratorTests.cs index 2616f4a..5d0c7ed 100644 --- a/Funzo.SourceGenerators.Test/ResultGeneratorTests.cs +++ b/Funzo.SourceGenerators.Test/ResultGeneratorTests.cs @@ -62,6 +62,14 @@ static TwoUnionResult process(int value) Assert.True(isOk); } + + [Fact] + public void Generates_Nested_Results() + { + InnerClass.InnerResult result = "test"; + + Assert.True(result.IsErr(out _)); + } } [Result] @@ -70,7 +78,7 @@ public partial class TestResult; public partial class TestUnitResult; [Union] -public partial class MyOk ; +public partial class MyOk; [Result] public partial class TwoUnionResult; @@ -82,4 +90,11 @@ public partial class ClonedErr; public partial class ClonedOk; [Result] -public partial class CheapClone; \ No newline at end of file +public partial class CheapClone; + + +public static partial class InnerClass +{ + [Result] + public partial class InnerResult; +} \ No newline at end of file diff --git a/Funzo.SourceGenerators.Test/UnionGeneratorTests.cs b/Funzo.SourceGenerators.Test/UnionGeneratorTests.cs index c28c21a..41c83c0 100644 --- a/Funzo.SourceGenerators.Test/UnionGeneratorTests.cs +++ b/Funzo.SourceGenerators.Test/UnionGeneratorTests.cs @@ -1,6 +1,7 @@ using System; namespace Funzo.SourceGenerators.Test; + public class UnionGeneratorTests { [Fact] @@ -42,6 +43,14 @@ public void Generates_Shared_Property() Assert.Equal("b", u2.Text); Assert.Equal("c", u3.Text); } + + [Fact] + public void Generates_Inner_Union() + { + TestUnionInPartialClass.InnerUnion u = new TestUnionInPartialClass.A(); + + u.Switch(a => { }, b => throw new InvalidOperationException()); + } } @@ -67,4 +76,14 @@ public class C(string text) { public string Text { get; set; } = text; public DateTime Date { get; set; } +} + + +public static partial class TestUnionInPartialClass +{ + public record A; + public record B; + + [Union] + public partial class InnerUnion; } \ No newline at end of file diff --git a/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs b/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs index 90dd09d..a8bb4cd 100644 --- a/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs +++ b/Funzo.SourceGenerators/Generators/ResultSourceGenerator.cs @@ -1,7 +1,11 @@ using Funzo.SourceGenerators.Generators.Results; using Funzo.SourceGenerators.Helpers; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using System; +using System.Linq; +using System.Text; namespace Funzo.SourceGenerators.Generators; @@ -20,11 +24,21 @@ internal class ResultSourceGenerator : SourceGeneratorBase ? new Result1AritySourceGenerator(symbolWithAttribute) : new Result2AritySourceGenerator(symbolWithAttribute); - var source = $@"// + var containingType = symbolWithAttribute.Symbol.ContainingType?.Name; + + var sb = new StringBuilder($@"// namespace {symbolWithAttribute.Symbol.ContainingNamespace.ToDisplayString()} -{{ - {generator.ClassDefinition} +{{"); + + if (containingType is not null) + { + var isStatic = symbolWithAttribute.Symbol.ContainingType!.IsStatic ? "static " : ""; + sb.AppendLine($"{isStatic}partial class {containingType} {{"); + } + + sb.AppendLine($@" + {generator.ClassDefinition} {{ {generator.OkConstructor} {generator.OkStaticHelper} @@ -33,15 +47,26 @@ namespace {symbolWithAttribute.Symbol.ContainingNamespace.ToDisplayString()} {generator.ErrStaticHelper} {generator.ErrImplicitConverter} }} -}}"; +}}"); - return source; + if (containingType is not null) + { + sb.AppendLine("}"); + } + + var src = sb.ToString(); + + return src; } private bool HasErrors(SourceProductionContext context, SymbolWithAttribute symbolWithAttribute) { var (ClassSymbol, _) = symbolWithAttribute; - if (!ClassSymbol.ContainingSymbol.Equals(ClassSymbol.ContainingNamespace, SymbolEqualityComparer.Default)) + + if (!ClassSymbol.ContainingSymbol.Equals(ClassSymbol.ContainingNamespace, SymbolEqualityComparer.Default) && ClassSymbol.ContainingType is { } containerType + && containerType.DeclaringSyntaxReferences.Any(syntax => + syntax.GetSyntax() is BaseTypeDeclarationSyntax declaration + && !declaration.Modifiers.Any(mod => mod.IsKind(SyntaxKind.PartialKeyword)))) { CreateDiagnosticError(context, FunzoDiagnosticDescriptors.Result.TopLevelError, ClassSymbol); return true; diff --git a/Funzo.SourceGenerators/Generators/Unions/UnionSourceGenerator.cs b/Funzo.SourceGenerators/Generators/Unions/UnionSourceGenerator.cs index c03f7b3..dc1b09c 100644 --- a/Funzo.SourceGenerators/Generators/Unions/UnionSourceGenerator.cs +++ b/Funzo.SourceGenerators/Generators/Unions/UnionSourceGenerator.cs @@ -1,5 +1,7 @@ using Funzo.SourceGenerators.Helpers; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Immutable; using System.Linq; @@ -22,11 +24,20 @@ internal class UnionSourceGenerator : SourceGeneratorBase var className = $"{classSymbol.Name}"; var typeArguments = symbolWithAttribute.TypeArguments; + var containingType = classSymbol.ContainingType?.Name; + StringBuilder source = new($@"// namespace {classSymbol.ContainingNamespace.ToDisplayString()} -{{ - partial class {className} : global::Funzo.Union{typeArguments.OpenGenericPart()} +{{"); + + if (containingType is not null) + { + var isStatic = classSymbol.IsStatic ? "static " : ""; + source.AppendLine($"{isStatic}partial class {containingType} {{"); + } + + source.AppendLine($@" partial class {className} : global::Funzo.Union{typeArguments.OpenGenericPart()} {{"); foreach (var type in typeArguments) @@ -37,7 +48,7 @@ partial class {className} : global::Funzo.Union{typeArguments.OpenGenericPart()} "); } - foreach(var prop in commonProperties) + foreach (var prop in commonProperties) { source.Append($@" public {prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {prop.Name} => Match({string.Join(",", Enumerable.Range(0, typeArguments.Length).Select(_ => $"x => x.{prop.Name}"))}); @@ -46,6 +57,10 @@ partial class {className} : global::Funzo.Union{typeArguments.OpenGenericPart()} source.Append(@" } }"); + if (containingType is not null) + { + source.AppendLine("}"); + } var src = source.ToString(); return src; @@ -56,8 +71,12 @@ private bool HasErrors(SourceProductionContext context, SymbolWithAttribute symb var (classSymbol, attributeData) = symbol; var attributeLocation = classSymbol.Locations.FirstOrDefault() ?? Location.None; - if (!classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.Default)) + if (!classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.Default) && classSymbol.ContainingType is { } containerType + && containerType.DeclaringSyntaxReferences.Any(syntax => + syntax.GetSyntax() is BaseTypeDeclarationSyntax declaration + && !declaration.Modifiers.Any(mod => mod.IsKind(SyntaxKind.PartialKeyword)))) { + System.Diagnostics.Debugger.Launch(); CreateDiagnosticError(context, FunzoDiagnosticDescriptors.Union.TopLevelError, classSymbol); return true; } diff --git a/Funzo.SourceGenerators/Helpers/FunzoDiagnosticDescriptors.cs b/Funzo.SourceGenerators/Helpers/FunzoDiagnosticDescriptors.cs index 4b862cb..1b224e9 100644 --- a/Funzo.SourceGenerators/Helpers/FunzoDiagnosticDescriptors.cs +++ b/Funzo.SourceGenerators/Helpers/FunzoDiagnosticDescriptors.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis; namespace Funzo.SourceGenerators.Helpers; + internal static class FunzoDiagnosticDescriptors { public static class Result @@ -8,7 +9,7 @@ public static class Result public static DiagnosticDescriptor TopLevelError => new("FNZ0001", "Class must be top level", - "Class '{0}' using ResultGenerator must be top level", + "Class '{0}' using ResultGenerator must be top level or inside a partial class", "ResultGenerator", DiagnosticSeverity.Error, true); @@ -33,7 +34,7 @@ public static class Union public static DiagnosticDescriptor TopLevelError => new("FNZ0004", "Class must be top level", - "Class '{0}' using UnionGenerator must be top level", + "Class '{0}' using UnionGenerator must be top level or inside a partial class", "UnionGenerator", DiagnosticSeverity.Error, true); diff --git a/Funzo/Union.generated.cs b/Funzo/Union.generated.cs index 8802118..26f326c 100644 --- a/Funzo/Union.generated.cs +++ b/Funzo/Union.generated.cs @@ -20,20 +20,20 @@ public abstract class UnionBase /// /// /// -public class Union : UnionBase, IEquatable> +public class Union : UnionBase, IEquatable> where T0 : notnull where T1 : notnull { /// /// Stores lazily all the types of this instance to easily check if matches another one /// - private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); + private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); internal override object GetValue() => _index switch { 0 => _value0!, - 1 => _value1!, +1 => _value1!, _ => throw new IndexOutOfRangeException("Union went out of range") }; @@ -41,41 +41,41 @@ internal override object GetValue() => private readonly int _index; private readonly T0 _value0 = default!; - private readonly T1 _value1 = default!; +private readonly T1 _value1 = default!; /// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T0 value) - { - _index = 0; +public Union(T0 value) +{ + _index = 0; - _value0 = value; - } + _value0 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T1 value) - { - _index = 1; +public Union(T1 value) +{ + _index = 1; - _value1 = value; - } + _value1 = value; +} /// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T0 x) => new(x); - /// +public static implicit operator Union(T0 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T1 x) => new(x); +public static implicit operator Union(T1 x) => new(x); /// /// Checks if this instance is of type and gets the value if it is @@ -86,7 +86,7 @@ public Union(T1 value) /// /// If this instance is of type , has its value assigned, otherwise /// if this instance is of type , otherwise - public bool Is([NotNullWhen(true)] out T? value) + public bool Is([NotNullWhen(true)]out T? value) { var valueType = GetValue().GetType(); var isSameType = valueType == typeof(T); @@ -107,41 +107,41 @@ public bool Is([NotNullWhen(true)] out T? value) /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - public void Switch(Action action0, Action action1) +/// The action to take if this instance is of type +public void Switch(Action action0,Action action1) +{ + switch(_index) { - switch (_index) - { - case 0: - action0(_value0); - return; - case 1: - action1(_value1); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } + case 0: + action0(_value0); + return; +case 1: + action1(_value1); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} - /// +/// /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - public async Task SwitchAsync(Func action0, Func action1) +/// The action to take if this instance is of type +public async Task SwitchAsync(Func action0,Func action1) +{ + switch(_index) { - switch (_index) - { - case 0: - await action0(_value0); - return; - case 1: - await action1(_value1); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } + case 0: + await action0(_value0); + return; +case 1: + await action1(_value1); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} /// @@ -149,21 +149,21 @@ public async Task SwitchAsync(Func action0, Func action1) /// /// /// - /// +/// /// - public TOut Match(Func func0, Func func1) +public TOut Match(Func func0,Func func1) +{ + return _index switch { - return _index switch - { - 0 => func0(_value0), - 1 => func1(_value1), - _ => throw new IndexOutOfRangeException("Union went out of range") - }; - } + 0 => func0(_value0), +1 => func1(_value1), + _ => throw new IndexOutOfRangeException("Union went out of range") + }; +} /// - public bool Equals(Union? other) + public bool Equals(Union? other) { return other is not null && other._index == _index && other.GetValue().Equals(GetValue()); } @@ -171,7 +171,7 @@ public bool Equals(Union? other) /// public override bool Equals(object? obj) { - return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); + return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); } /// @@ -183,7 +183,7 @@ internal bool Equals(UnionBase other) /// public override int GetHashCode() { -#if NETSTANDARD2_0 + #if NETSTANDARD2_0 unchecked { return (GetValue().GetHashCode() * 397) ^ _index; @@ -202,7 +202,7 @@ public override int GetHashCode() /// /// /// -public class Union : UnionBase, IEquatable> +public class Union : UnionBase, IEquatable> where T0 : notnull where T1 : notnull where T2 : notnull @@ -210,14 +210,14 @@ public class Union : UnionBase, IEquatable> /// /// Stores lazily all the types of this instance to easily check if matches another one /// - private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); + private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); internal override object GetValue() => _index switch { 0 => _value0!, - 1 => _value1!, - 2 => _value2!, +1 => _value1!, +2 => _value2!, _ => throw new IndexOutOfRangeException("Union went out of range") }; @@ -225,58 +225,58 @@ internal override object GetValue() => private readonly int _index; private readonly T0 _value0 = default!; - private readonly T1 _value1 = default!; - private readonly T2 _value2 = default!; +private readonly T1 _value1 = default!; +private readonly T2 _value2 = default!; /// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T0 value) - { - _index = 0; +public Union(T0 value) +{ + _index = 0; - _value0 = value; - } + _value0 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T1 value) - { - _index = 1; +public Union(T1 value) +{ + _index = 1; - _value1 = value; - } + _value1 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T2 value) - { - _index = 2; +public Union(T2 value) +{ + _index = 2; - _value2 = value; - } + _value2 = value; +} /// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T0 x) => new(x); - /// +public static implicit operator Union(T0 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T1 x) => new(x); - /// +public static implicit operator Union(T1 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T2 x) => new(x); +public static implicit operator Union(T2 x) => new(x); /// /// Checks if this instance is of type and gets the value if it is @@ -287,7 +287,7 @@ public Union(T2 value) /// /// If this instance is of type , has its value assigned, otherwise /// if this instance is of type , otherwise - public bool Is([NotNullWhen(true)] out T? value) + public bool Is([NotNullWhen(true)]out T? value) { var valueType = GetValue().GetType(); var isSameType = valueType == typeof(T); @@ -308,49 +308,49 @@ public bool Is([NotNullWhen(true)] out T? value) /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - public void Switch(Action action0, Action action1, Action action2) - { - switch (_index) - { - case 0: - action0(_value0); - return; - case 1: - action1(_value1); - return; - case 2: - action2(_value2); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } +/// The action to take if this instance is of type +/// The action to take if this instance is of type +public void Switch(Action action0,Action action1,Action action2) +{ + switch(_index) + { + case 0: + action0(_value0); + return; +case 1: + action1(_value1); + return; +case 2: + action2(_value2); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} - /// +/// /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - public async Task SwitchAsync(Func action0, Func action1, Func action2) - { - switch (_index) - { - case 0: - await action0(_value0); - return; - case 1: - await action1(_value1); - return; - case 2: - await action2(_value2); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } +/// The action to take if this instance is of type +/// The action to take if this instance is of type +public async Task SwitchAsync(Func action0,Func action1,Func action2) +{ + switch(_index) + { + case 0: + await action0(_value0); + return; +case 1: + await action1(_value1); + return; +case 2: + await action2(_value2); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} /// @@ -358,23 +358,23 @@ public async Task SwitchAsync(Func action0, Func action1, Fu /// /// /// - /// - /// +/// +/// /// - public TOut Match(Func func0, Func func1, Func func2) +public TOut Match(Func func0,Func func1,Func func2) +{ + return _index switch { - return _index switch - { - 0 => func0(_value0), - 1 => func1(_value1), - 2 => func2(_value2), - _ => throw new IndexOutOfRangeException("Union went out of range") - }; - } + 0 => func0(_value0), +1 => func1(_value1), +2 => func2(_value2), + _ => throw new IndexOutOfRangeException("Union went out of range") + }; +} /// - public bool Equals(Union? other) + public bool Equals(Union? other) { return other is not null && other._index == _index && other.GetValue().Equals(GetValue()); } @@ -382,7 +382,7 @@ public bool Equals(Union? other) /// public override bool Equals(object? obj) { - return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); + return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); } /// @@ -394,7 +394,7 @@ internal bool Equals(UnionBase other) /// public override int GetHashCode() { -#if NETSTANDARD2_0 + #if NETSTANDARD2_0 unchecked { return (GetValue().GetHashCode() * 397) ^ _index; @@ -414,7 +414,7 @@ public override int GetHashCode() /// /// /// -public class Union : UnionBase, IEquatable> +public class Union : UnionBase, IEquatable> where T0 : notnull where T1 : notnull where T2 : notnull @@ -423,15 +423,15 @@ public class Union : UnionBase, IEquatable /// /// Stores lazily all the types of this instance to easily check if matches another one /// - private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); + private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); internal override object GetValue() => _index switch { 0 => _value0!, - 1 => _value1!, - 2 => _value2!, - 3 => _value3!, +1 => _value1!, +2 => _value2!, +3 => _value3!, _ => throw new IndexOutOfRangeException("Union went out of range") }; @@ -439,75 +439,75 @@ internal override object GetValue() => private readonly int _index; private readonly T0 _value0 = default!; - private readonly T1 _value1 = default!; - private readonly T2 _value2 = default!; - private readonly T3 _value3 = default!; +private readonly T1 _value1 = default!; +private readonly T2 _value2 = default!; +private readonly T3 _value3 = default!; /// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T0 value) - { - _index = 0; +public Union(T0 value) +{ + _index = 0; - _value0 = value; - } + _value0 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T1 value) - { - _index = 1; +public Union(T1 value) +{ + _index = 1; - _value1 = value; - } + _value1 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T2 value) - { - _index = 2; +public Union(T2 value) +{ + _index = 2; - _value2 = value; - } + _value2 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T3 value) - { - _index = 3; +public Union(T3 value) +{ + _index = 3; - _value3 = value; - } + _value3 = value; +} /// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T0 x) => new(x); - /// +public static implicit operator Union(T0 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T1 x) => new(x); - /// +public static implicit operator Union(T1 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T2 x) => new(x); - /// +public static implicit operator Union(T2 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T3 x) => new(x); +public static implicit operator Union(T3 x) => new(x); /// /// Checks if this instance is of type and gets the value if it is @@ -518,7 +518,7 @@ public Union(T3 value) /// /// If this instance is of type , has its value assigned, otherwise /// if this instance is of type , otherwise - public bool Is([NotNullWhen(true)] out T? value) + public bool Is([NotNullWhen(true)]out T? value) { var valueType = GetValue().GetType(); var isSameType = valueType == typeof(T); @@ -539,57 +539,57 @@ public bool Is([NotNullWhen(true)] out T? value) /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - public void Switch(Action action0, Action action1, Action action2, Action action3) - { - switch (_index) - { - case 0: - action0(_value0); - return; - case 1: - action1(_value1); - return; - case 2: - action2(_value2); - return; - case 3: - action3(_value3); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } +/// The action to take if this instance is of type +/// The action to take if this instance is of type +/// The action to take if this instance is of type +public void Switch(Action action0,Action action1,Action action2,Action action3) +{ + switch(_index) + { + case 0: + action0(_value0); + return; +case 1: + action1(_value1); + return; +case 2: + action2(_value2); + return; +case 3: + action3(_value3); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} - /// +/// /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - public async Task SwitchAsync(Func action0, Func action1, Func action2, Func action3) - { - switch (_index) - { - case 0: - await action0(_value0); - return; - case 1: - await action1(_value1); - return; - case 2: - await action2(_value2); - return; - case 3: - await action3(_value3); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } +/// The action to take if this instance is of type +/// The action to take if this instance is of type +/// The action to take if this instance is of type +public async Task SwitchAsync(Func action0,Func action1,Func action2,Func action3) +{ + switch(_index) + { + case 0: + await action0(_value0); + return; +case 1: + await action1(_value1); + return; +case 2: + await action2(_value2); + return; +case 3: + await action3(_value3); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} /// @@ -597,25 +597,25 @@ public async Task SwitchAsync(Func action0, Func action1, Fu /// /// /// - /// - /// - /// +/// +/// +/// /// - public TOut Match(Func func0, Func func1, Func func2, Func func3) - { - return _index switch - { - 0 => func0(_value0), - 1 => func1(_value1), - 2 => func2(_value2), - 3 => func3(_value3), - _ => throw new IndexOutOfRangeException("Union went out of range") - }; - } +public TOut Match(Func func0,Func func1,Func func2,Func func3) +{ + return _index switch + { + 0 => func0(_value0), +1 => func1(_value1), +2 => func2(_value2), +3 => func3(_value3), + _ => throw new IndexOutOfRangeException("Union went out of range") + }; +} /// - public bool Equals(Union? other) + public bool Equals(Union? other) { return other is not null && other._index == _index && other.GetValue().Equals(GetValue()); } @@ -623,7 +623,7 @@ public bool Equals(Union? other) /// public override bool Equals(object? obj) { - return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); + return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); } /// @@ -635,7 +635,7 @@ internal bool Equals(UnionBase other) /// public override int GetHashCode() { -#if NETSTANDARD2_0 + #if NETSTANDARD2_0 unchecked { return (GetValue().GetHashCode() * 397) ^ _index; @@ -656,7 +656,7 @@ public override int GetHashCode() /// /// /// -public class Union : UnionBase, IEquatable> +public class Union : UnionBase, IEquatable> where T0 : notnull where T1 : notnull where T2 : notnull @@ -666,16 +666,16 @@ public class Union : UnionBase, IEquatable /// Stores lazily all the types of this instance to easily check if matches another one /// - private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); + private static readonly Lazy UnionTypeDefinitions = new(() => typeof(Union).GetGenericArguments()); internal override object GetValue() => _index switch { 0 => _value0!, - 1 => _value1!, - 2 => _value2!, - 3 => _value3!, - 4 => _value4!, +1 => _value1!, +2 => _value2!, +3 => _value3!, +4 => _value4!, _ => throw new IndexOutOfRangeException("Union went out of range") }; @@ -683,92 +683,92 @@ internal override object GetValue() => private readonly int _index; private readonly T0 _value0 = default!; - private readonly T1 _value1 = default!; - private readonly T2 _value2 = default!; - private readonly T3 _value3 = default!; - private readonly T4 _value4 = default!; +private readonly T1 _value1 = default!; +private readonly T2 _value2 = default!; +private readonly T3 _value3 = default!; +private readonly T4 _value4 = default!; /// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T0 value) - { - _index = 0; +public Union(T0 value) +{ + _index = 0; - _value0 = value; - } + _value0 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T1 value) - { - _index = 1; +public Union(T1 value) +{ + _index = 1; - _value1 = value; - } + _value1 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T2 value) - { - _index = 2; +public Union(T2 value) +{ + _index = 2; - _value2 = value; - } + _value2 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T3 value) - { - _index = 3; +public Union(T3 value) +{ + _index = 3; - _value3 = value; - } + _value3 = value; +} - /// +/// /// Create an instance of with the type /// /// The value to initialize this instance" - public Union(T4 value) - { - _index = 4; +public Union(T4 value) +{ + _index = 4; - _value4 = value; - } + _value4 = value; +} /// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T0 x) => new(x); - /// +public static implicit operator Union(T0 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T1 x) => new(x); - /// +public static implicit operator Union(T1 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T2 x) => new(x); - /// +public static implicit operator Union(T2 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T3 x) => new(x); - /// +public static implicit operator Union(T3 x) => new(x); +/// /// Implicitly converts into /// /// The value to convert from - public static implicit operator Union(T4 x) => new(x); +public static implicit operator Union(T4 x) => new(x); /// /// Checks if this instance is of type and gets the value if it is @@ -779,7 +779,7 @@ public Union(T4 value) /// /// If this instance is of type , has its value assigned, otherwise /// if this instance is of type , otherwise - public bool Is([NotNullWhen(true)] out T? value) + public bool Is([NotNullWhen(true)]out T? value) { var valueType = GetValue().GetType(); var isSameType = valueType == typeof(T); @@ -800,65 +800,65 @@ public bool Is([NotNullWhen(true)] out T? value) /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - public void Switch(Action action0, Action action1, Action action2, Action action3, Action action4) - { - switch (_index) - { - case 0: - action0(_value0); - return; - case 1: - action1(_value1); - return; - case 2: - action2(_value2); - return; - case 3: - action3(_value3); - return; - case 4: - action4(_value4); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } +/// The action to take if this instance is of type +/// The action to take if this instance is of type +/// The action to take if this instance is of type +/// The action to take if this instance is of type +public void Switch(Action action0,Action action1,Action action2,Action action3,Action action4) +{ + switch(_index) + { + case 0: + action0(_value0); + return; +case 1: + action1(_value1); + return; +case 2: + action2(_value2); + return; +case 3: + action3(_value3); + return; +case 4: + action4(_value4); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} - /// +/// /// Executes an action based on the type of this instance /// /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - /// The action to take if this instance is of type - public async Task SwitchAsync(Func action0, Func action1, Func action2, Func action3, Func action4) - { - switch (_index) - { - case 0: - await action0(_value0); - return; - case 1: - await action1(_value1); - return; - case 2: - await action2(_value2); - return; - case 3: - await action3(_value3); - return; - case 4: - await action4(_value4); - return; - default: - throw new IndexOutOfRangeException("Union went out of range"); - } +/// The action to take if this instance is of type +/// The action to take if this instance is of type +/// The action to take if this instance is of type +/// The action to take if this instance is of type +public async Task SwitchAsync(Func action0,Func action1,Func action2,Func action3,Func action4) +{ + switch(_index) + { + case 0: + await action0(_value0); + return; +case 1: + await action1(_value1); + return; +case 2: + await action2(_value2); + return; +case 3: + await action3(_value3); + return; +case 4: + await action4(_value4); + return; + default: + throw new IndexOutOfRangeException("Union went out of range"); } +} /// @@ -866,27 +866,27 @@ public async Task SwitchAsync(Func action0, Func action1, Fu /// /// /// - /// - /// - /// - /// +/// +/// +/// +/// /// - public TOut Match(Func func0, Func func1, Func func2, Func func3, Func func4) - { - return _index switch - { - 0 => func0(_value0), - 1 => func1(_value1), - 2 => func2(_value2), - 3 => func3(_value3), - 4 => func4(_value4), - _ => throw new IndexOutOfRangeException("Union went out of range") - }; - } +public TOut Match(Func func0,Func func1,Func func2,Func func3,Func func4) +{ + return _index switch + { + 0 => func0(_value0), +1 => func1(_value1), +2 => func2(_value2), +3 => func3(_value3), +4 => func4(_value4), + _ => throw new IndexOutOfRangeException("Union went out of range") + }; +} /// - public bool Equals(Union? other) + public bool Equals(Union? other) { return other is not null && other._index == _index && other.GetValue().Equals(GetValue()); } @@ -894,7 +894,7 @@ public bool Equals(Union? other) /// public override bool Equals(object? obj) { - return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); + return obj is Union union && union.Equals(this) || obj is UnionBase u && this.Equals(u); } /// @@ -906,7 +906,7 @@ internal bool Equals(UnionBase other) /// public override int GetHashCode() { -#if NETSTANDARD2_0 + #if NETSTANDARD2_0 unchecked { return (GetValue().GetHashCode() * 397) ^ _index; From 64c892e8b66ce81fc450593dbdb485e7d7cf4b13 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Bastida Date: Sat, 3 Jan 2026 10:18:21 +0100 Subject: [PATCH 5/5] Update CI --- .github/workflows/build-ci.yml | 29 +++++++++++---------- .github/workflows/release.yml | 46 ++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index a1e0d19..3327ac8 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -5,24 +5,23 @@ name: .NET on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] jobs: build: - runs-on: windows-2025 + runs-on: ubuntu-latest timeout-minutes: 5 steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup .NET SDK - uses: actions/setup-dotnet@v4 - with: - dotnet-version: | - 9.0.x - 5.0.x - - name: Build - run: dotnet build -c Release - - name: Test - run: dotnet test -c Release + - name: Checkout + uses: actions/checkout@v2 + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 10.0.x + - name: Build + run: dotnet build -c Release + - name: Test + run: dotnet test -c Release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 84b2009..58ceeba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,29 +3,31 @@ name: Release to NuGet on: release: types: [published] - + +env: + VERSION: ${{ github.event.release.draft && format('{0}-beta', github.event.release.tag_name) || github.event.release.tag_name }} + jobs: build: - runs-on: windows-2025 + runs-on: ubuntu-latest timeout-minutes: 5 steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup .NET SDK - uses: actions/setup-dotnet@v4 - with: - dotnet-version: | - 9.0.x - 5.0.x - - name: Build - run: dotnet build -c Release /p:Version=${{github.event.release.tag_name}} - - name: Test - run: dotnet test -c Release --no-build - - name: Pack Funzo - run: dotnet pack Funzo -c Release --no-build --output . /p:PackageVersion=${{github.event.release.tag_name}} - - name: Pack Serialization - run: dotnet pack Funzo.Serialization -c Release --no-build --output . /p:PackageVersion=${{github.event.release.tag_name}} - - name: Pack Source Generators - run: dotnet pack Funzo.SourceGenerators -c Release --no-build --output . /p:PackageVersion=${{github.event.release.tag_name}} - - name: Push to NuGet - run: dotnet nuget push "*.nupkg" --api-key ${{secrets.nuget_api_key}} --source https://api.nuget.org/v3/index.json + - name: Checkout + uses: actions/checkout@v2 + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 10.0.x + - name: Build + run: dotnet build -c Release /p:Version=$VERSION + - name: Test + run: dotnet test -c Release --no-build + - name: Pack Funzo + run: dotnet pack Funzo -c Release --no-build --output . /p:PackageVersion=$VERSION + - name: Pack Serialization + run: dotnet pack Funzo.Serialization -c Release --no-build --output . /p:PackageVersion=$VERSION + - name: Pack Source Generators + run: dotnet pack Funzo.SourceGenerators -c Release --no-build --output . /p:PackageVersion=$VERSION + - name: Push to NuGet + run: dotnet nuget push "*.nupkg" --api-key ${{secrets.nuget_api_key}} --source https://api.nuget.org/v3/index.json