Skip to content

Implement NewType pattern for VoiceModelId to improve type safety #215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions src/VoicevoxCoreSharp.Core/Synthesizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,22 @@ public ResultCode LoadVoiceModel(VoiceModelFile voiceModel)
}
}

public ResultCode UnloadVoiceModel(string modelId)
public ResultCode UnloadVoiceModel(VoiceModelId modelId)
{
unsafe
{
fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId))
fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId.Id))
{
return CoreUnsafe.voicevox_synthesizer_unload_voice_model((VoicevoxSynthesizer*)Handle, ptr).FromNative();
}
}
}

// For backward compatibility
public ResultCode UnloadVoiceModel(string modelId)
{
return UnloadVoiceModel(new VoiceModelId(modelId));
}

public bool IsGpuMode
{
Expand All @@ -90,16 +96,22 @@ public bool IsGpuMode
}
}

public bool IsLoadedVoiceModel(string modelId)
public bool IsLoadedVoiceModel(VoiceModelId modelId)
{
unsafe
{
fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId))
fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId.Id))
{
return CoreUnsafe.voicevox_synthesizer_is_loaded_voice_model((VoicevoxSynthesizer*)Handle, ptr);
}
}
}

// For backward compatibility
public bool IsLoadedVoiceModel(string modelId)
{
return IsLoadedVoiceModel(new VoiceModelId(modelId));
}

public string MetasJson
{
Expand Down
6 changes: 3 additions & 3 deletions src/VoicevoxCoreSharp.Core/VoiceModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,21 @@ public class VoiceModelFile : IDisposable
internal VoiceModelFileHandle Handle { get; private set; }
private bool _disposed = false;

public string Id { get; private set; }
public VoiceModelId Id { get; private set; }

public string MetasJson { get; private set; }

private VoiceModelFile()
{
Handle = new VoiceModelFileHandle(IntPtr.Zero);
Id = string.Empty;
Id = new VoiceModelId(string.Empty);
MetasJson = string.Empty;
}

private unsafe VoiceModelFile(VoicevoxVoiceModelFile* modelHandle, string id, string metasJson)
{
Handle = new VoiceModelFileHandle(new IntPtr(modelHandle));
Id = id;
Id = new VoiceModelId(id);
MetasJson = metasJson;
}

Expand Down
16 changes: 16 additions & 0 deletions src/VoicevoxCoreSharp.Core/VoiceModelId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace VoicevoxCoreSharp.Core
{
public record VoiceModelId(string Id)
{
// Target framework is netstandard2.0, so init-only properties not available
public string Id { get; } = Id;

public static implicit operator string(VoiceModelId id) => id.Id;

public static implicit operator VoiceModelId(string id) => new VoiceModelId(id);

public override string ToString() => Id;
}
}
1 change: 1 addition & 0 deletions tests/VoicevoxCoreSharp.Core.Tests/SynthesizerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void VoiceModelLoaded()
VoiceModelFile.Open(Consts.SampleVoiceModel, out var voiceModel);
synthesizer.LoadVoiceModel(voiceModel);

// The IsLoadedVoiceModel and UnloadVoiceModel methods should work with the VoiceModelId type
Assert.True(synthesizer.IsLoadedVoiceModel(voiceModel.Id));
synthesizer.UnloadVoiceModel(voiceModel.Id);
Assert.False(synthesizer.IsLoadedVoiceModel(voiceModel.Id));
Expand Down
38 changes: 38 additions & 0 deletions tests/VoicevoxCoreSharp.Core.Tests/VoiceModelIdTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using Xunit;

namespace VoicevoxCoreSharp.Core.Tests
{
public class VoiceModelIdTest
{
[Fact]
public void CreateAndConvertToString()
{
var id = new VoiceModelId("test-id");
Assert.Equal("test-id", id.Id);
Assert.Equal("test-id", id.ToString());

// Test implicit conversion to string
string idString = id;
Assert.Equal("test-id", idString);
}

[Fact]
public void CreateFromString()
{
VoiceModelId id = "test-id";
Assert.Equal("test-id", id.Id);
}

[Fact]
public void Equality()
{
var id1 = new VoiceModelId("test-id");
var id2 = new VoiceModelId("test-id");
var id3 = new VoiceModelId("different-id");

Assert.Equal(id1, id2);
Assert.NotEqual(id1, id3);
}
}
}
6 changes: 3 additions & 3 deletions tests/VoicevoxCoreSharp.Core.Tests/VoiceModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public void Open()
Assert.Equal(ResultCode.RESULT_OK, openResult);
Assert.NotNull(voiceModel);

Assert.NotEmpty(voiceModel.Id);
Assert.NotEmpty(voiceModel.Id.Id);
Assert.NotEmpty(voiceModel.MetasJson);
}

Expand All @@ -23,10 +23,10 @@ public void AccessMemberAfterDisposed()
var _ = VoiceModelFile.Open(Consts.SampleVoiceModel, out var voiceModel);
using (voiceModel) { }

Assert.NotEmpty(voiceModel.Id);
Assert.NotEmpty(voiceModel.Id.Id);
Assert.NotEmpty(voiceModel.MetasJson);

Assert.True(voiceModel.Id.Length > 0);
Assert.True(voiceModel.Id.Id.Length > 0);
Assert.True(voiceModel.MetasJson.Length > 0);
}
}
Expand Down