ScottEncodingGenerator

RSCG – ScottEncodingGenerator
 
 

name ScottEncodingGenerator
nuget https://www.nuget.org/packages/ScottEncodingGenerator/
link https://github.com/Georgiy-Petrov/ScottEncodingGenerator
author Georgiy Petrov

Usage

1. You declare a union-like type as an abstract partial class and annotate it with ScottEncoding.

2. Inside it, you define each case as a sealed partial nested class (in this sample: Ok and None).

3. Your business logic returns one of those cases (Ok when save succeeds, None when it does not).

4. Consumer code can handle results either with normal C# pattern matching or with the generated functional matching API.

2. What the generator adds

1. A Match contract on the parent union type, plus per-case implementations that dispatch to the correct handler.

2. A companion module with factory helpers to construct each case (Ok / None) without directly calling constructors.

3. A fluent matching flow (IfOk(…).IfNone(…)) built on top of Match.

4. A generated ScottEncodingAttribute definition, so the attribute is available at compile time.

 

This is how you can use ScottEncodingGenerator .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="ScottEncodingGenerator" Version="1.0.0" />
	</ItemGroup>

	

</Project>


The code that you will use is


using UnionTypesDemo;

Console.WriteLine("Save or not");
ResultSave<int> data = SaveToDatabase.Save(0);
var message= data switch
{
    ResultSave<int>.Ok ok => $"Saved {ok.Value}",
    ResultSave<int>.None => "Not found", 
};
Console.WriteLine(message);
data = SaveToDatabase.Save(1);
message = data.Match(

    ok => $"Saved {ok.Value}",
    none => "Not found"   
 );
Console.WriteLine(message);





namespace UnionTypesDemo;


[ScottEncoding]
public abstract partial class ResultSave<T>
{

    public sealed partial class Ok
    {
        public Ok(T value) => Value = value;
        public T Value { get; }
    }

    public sealed partial class None
    {
        public None() { }
    }

}




namespace UnionTypesDemo;

public class SaveToDatabase
{
    public static ResultSave<int> Save(int i)
    {

        if (i == 0)
        {
            return new ResultSave<int>.None();
        }
        return new ResultSave<int>.Ok(i); 
    }
}




 

The code that is generated is

// <auto-generated />
#nullable enable

namespace UnionTypesDemo
{
    public abstract partial class ResultSave<T>
    {
        public abstract TResult Match<TResult>(global::System.Func<global::UnionTypesDemo.ResultSave<T>.Ok, TResult> ok, global::System.Func<global::UnionTypesDemo.ResultSave<T>.None, TResult> none);
    
        public sealed partial class Ok : global::UnionTypesDemo.ResultSave<T>
        {
            public override TResult Match<TResult>(global::System.Func<global::UnionTypesDemo.ResultSave<T>.Ok, TResult> ok, global::System.Func<global::UnionTypesDemo.ResultSave<T>.None, TResult> none) => ok(this);
        }
    
        public sealed partial class None : global::UnionTypesDemo.ResultSave<T>
        {
            public override TResult Match<TResult>(global::System.Func<global::UnionTypesDemo.ResultSave<T>.Ok, TResult> ok, global::System.Func<global::UnionTypesDemo.ResultSave<T>.None, TResult> none) => none(this);
        }
    }

    public static partial class ResultSaveModule
    {
        public static global::UnionTypesDemo.ResultSave<T> Ok<T>(T value) => new global::UnionTypesDemo.ResultSave<T>.Ok(value);
    
        public static global::UnionTypesDemo.ResultSave<T> None<T>() => new global::UnionTypesDemo.ResultSave<T>.None();
    
        public static MatchStep2<T, TResult> IfOk<T, TResult>(this global::UnionTypesDemo.ResultSave<T> value, global::System.Func<global::UnionTypesDemo.ResultSave<T>.Ok, TResult> ok) => new(value, ok);
    
        public readonly struct MatchStep2<T, TResult>

        {

            private readonly global::UnionTypesDemo.ResultSave<T> _value;

            private readonly global::System.Func<global::UnionTypesDemo.ResultSave<T>.Ok, TResult> _ok;

        

            public MatchStep2(global::UnionTypesDemo.ResultSave<T> value, global::System.Func<global::UnionTypesDemo.ResultSave<T>.Ok, TResult> ok)

            {

                _value = value;

                _ok = ok;

            }

        

            public TResult IfNone(global::System.Func<global::UnionTypesDemo.ResultSave<T>.None, TResult> none) => _value.Match(_ok, none);

        }
    }
}

using System;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
internal sealed class ScottEncodingAttribute : Attribute
{
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/ScottEncodingGenerator


Posted

in

by

Tags: