zompinc / sync-method-generator

Generates a synchronized version of an async method
MIT License
48 stars 4 forks source link

Generate sync classes #70

Closed GerardSmit closed 1 month ago

GerardSmit commented 6 months ago

This PR adds the ability to add [CreateSyncVersion] to classes and renaming the resulting class/method name.

Problem

I'm trying to make an async file system for the library Zio, but I'm trying not to duplicate code from the async and sync filesystem.

The design is as following:

interface IAsyncFileSystem
{
    Task<string> ReadAllTextAsync(string path);

    Task WriteAllTextAsync(string path, string contents);
}

interface IFileSystem : IAsyncFileSystem
{
    string ReadAllText(string path);

    void WriteAllText(string path, string contents);
}

The interface IAsyncFileSystem has all the async-methods.
The interface IFileSystem implements IAsyncFileSystem and has all the sync-methods.

The implementation of the async file system contains the async methods:

internal class AsyncFileSystem : IAsyncFileSystem
{
    public virtual Task<string> ReadAllTextAsync(string path) => Task.FromResult("");

    public virtual Task WriteAllTextAsync(string path, string contents) => Task.CompletedTask;
}

The implementation of the sync file system overrides the async methods and calls the sync versions:

internal partial class FileSystem : AsyncFileSystem, IFileSystem
{
    public override Task<string> ReadAllTextAsync(string path) => Task.FromResult(ReadAllText(path));

    public override Task WriteAllTextAsync(string path, string contents)
    {
        WriteAllText(path, contents);
        return Task.CompletedTask;
    }
}

The class doesn't have the sync version of ReadAllTextAsync and WriteAllTextAsync and I want to generate them.

However, the source generator doesn't currently have the ability to generate the methods to a different class. Only the current class.

Solution

This PR adds two things:

  1. [CreateSyncVersion] can be added to classes to generate sync-versions of methods of all methods in the class.
  2. [CreateSyncVersion] has a new parameter to override the auto-generated name, this can be used for the class.

For the problem I can now add [CreateSyncVersion] to the class and override the class name:

[Zomp.SyncMethodGenerator.CreateSyncVersion(Name = "FileSystem")]
internal class AsyncFileSystem : IAsyncFileSystem
{
    public virtual Task<string> ReadAllTextAsync(string path) => Task.FromResult("");

    public virtual Task WriteAllTextAsync(string path, string contents) => Task.CompletedTask;
}

Which generates the following code:

Test.Test.FileSystem.WriteAllTextAsync.g.cs

namespace Test;
internal partial class FileSystem
{
    public virtual string ReadAllText(string path) => "";
}

Test.Test.FileSystem.ReadAllTextAsync.g.cs

namespace Test;
internal partial class FileSystem
{
    public virtual void WriteAllText(string path, string contents) { }
}

Considerations

I could also add a new argument called ClassName instead of Name and disallow [CreateSyncVersion] on classes. Feel free to discuss this in this PR 😄

virzak commented 6 months ago

Hi @GerardSmit,

First of all, thank you for integrating this into other libraries!!!

Here are my thoughts: