// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Collections.Concurrent;
using System.Text;
namespace SharpEmu.ShaderCompiler.Metal;
///
/// Loads the static MSL blocks from embedded Templates/*.msl resources and
/// substitutes {{placeholder}} tokens. The static prelude and fixed shaders
/// are authored as real Metal source files; only the per-instruction body
/// emission stays programmatic in the translator.
///
internal static class MslTemplates
{
private static readonly ConcurrentDictionary _cache = new(StringComparer.Ordinal);
public static string Render(string name, params (string Key, string Value)[] substitutions)
{
var template = _cache.GetOrAdd(name, Load);
if (substitutions.Length == 0)
{
return template;
}
var builder = new StringBuilder(template);
foreach (var (key, value) in substitutions)
{
builder.Replace("{{" + key + "}}", value);
}
var rendered = builder.ToString();
var marker = rendered.IndexOf("{{", StringComparison.Ordinal);
if (marker >= 0)
{
var end = rendered.IndexOf("}}", marker, StringComparison.Ordinal);
var token = end > marker ? rendered[marker..(end + 2)] : "{{...";
throw new InvalidOperationException(
$"template '{name}' has an unsubstituted placeholder {token}");
}
return rendered;
}
private static string Load(string name)
{
var assembly = typeof(MslTemplates).Assembly;
var resourceName = $"SharpEmu.ShaderCompiler.Metal.Templates.{name}.msl";
using var stream = assembly.GetManifestResourceStream(resourceName)
?? throw new InvalidOperationException($"missing embedded MSL template {resourceName}");
using var reader = new StreamReader(stream, Encoding.UTF8);
return reader.ReadToEnd();
}
}