diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3da7d77..1d260b4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -14,5 +14,6 @@ - Added support for compiling Typst documents with multiple PDF standards simultaneously (e.g. `v-1.7`, `a-2b`, etc.) by exposing a `pdfStandards` parameter in the `TypstCompiler.Compile` API, leveraging the underlying `typst-pdf` crate updates in Typst 0.15. ### Changed +- `sysInputs` parameters on `TypstCompiler` and the `SetSysInputs` argument are now `IDictionary` instead of `Dictionary`, so a `ReadOnlyDictionary`, `ImmutableDictionary` or any other implementation can be passed. Existing calls that pass a `Dictionary` are unaffected. - `compiler.CompilePdf(Stream)`, `compiler.CompilePdfAsync(Stream)`, `compiler.CompilePdf(string outputFile)` and `compiler.CompilePdfAsync(string outputFile)` now stream the document straight from native memory to the destination and return the compiler warnings, rather than returning a `PdfResult` that had to be materialised on the managed heap first. Use `compiler.CompilePdf()` when you want the bytes. - `compiler.Compile(outputFile, format)` and `compiler.CompileSvg(...)` no longer copy the rendered output onto the managed heap before writing or decoding it. diff --git a/src/typstsharp.tests/Tests.cs b/src/typstsharp.tests/Tests.cs index 475e46c..47e653a 100644 --- a/src/typstsharp.tests/Tests.cs +++ b/src/typstsharp.tests/Tests.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using System.Text; using UglyToad.PdfPig; using UglyToad.PdfPig.Content; @@ -244,6 +245,28 @@ public async Task ErrorWithNullByteIsHandledCorrectly() await Assert.That(ex!.Message).Contains("foo\0bar"); } + [Test] + public async Task SysInputsParameterAcceptsReadOnlyDictionary() + { + var sysInputs = new ReadOnlyDictionary( + new Dictionary { ["greeting"] = "Hello Inputs" }); + + using var compiler = TypstCompiler.FromSource("#sys.inputs.greeting", sysInputs: sysInputs); + var plainText = GetPlainText(compiler.CompilePdf()); + await Assert.That(plainText).Contains("Hello Inputs"); + } + + [Test] + public async Task SetSysInputsAcceptsReadOnlyDictionary() + { + using var compiler = TypstCompiler.FromSource("#sys.inputs.greeting"); + compiler.SetSysInputs(new ReadOnlyDictionary( + new Dictionary { ["greeting"] = "Hello Later" })); + + var plainText = GetPlainText(compiler.CompilePdf()); + await Assert.That(plainText).Contains("Hello Later"); + } + [Test] public async Task SourceAfterNullByteIsNotTruncated() { diff --git a/src/typstsharp/JsonSerialisation.cs b/src/typstsharp/JsonSerialisation.cs index 1decda4..5605cf5 100644 --- a/src/typstsharp/JsonSerialisation.cs +++ b/src/typstsharp/JsonSerialisation.cs @@ -8,5 +8,5 @@ namespace typstsharp; [JsonSourceGenerationOptions(WriteIndented = true)] -[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(IDictionary))] internal partial class SourceGenerationContext : JsonSerializerContext { } \ No newline at end of file diff --git a/src/typstsharp/TypstCompiler.cs b/src/typstsharp/TypstCompiler.cs index bbf1b22..079f319 100644 --- a/src/typstsharp/TypstCompiler.cs +++ b/src/typstsharp/TypstCompiler.cs @@ -34,7 +34,7 @@ public class TypstCompiler : IDisposable /// that directory, which keeps compilation off the network. /// /// Thrown when the Typst compiler fails to initialize. - public TypstCompiler(string inputPath, Fonts? fonts = null, Dictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) + public TypstCompiler(string inputPath, Fonts? fonts = null, IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) : this(inputPath, null, fonts, sysInputs, root, packagePath, includeSystemPackages) { } @@ -53,7 +53,7 @@ public TypstCompiler(string inputPath, Fonts? fonts = null, Dictionary /// A new instance. - public static TypstCompiler FromSource(string source, Fonts? fonts = null, Dictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) + public static TypstCompiler FromSource(string source, Fonts? fonts = null, IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) { return new TypstCompiler(null, source, fonts, sysInputs, root, packagePath, includeSystemPackages); } @@ -72,7 +72,7 @@ public static TypstCompiler FromSource(string source, Fonts? fonts = null, Dicti /// that directory, which keeps compilation off the network. /// /// A new instance. - public static TypstCompiler FromFile(string path, Fonts? fonts = null, Dictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) + public static TypstCompiler FromFile(string path, Fonts? fonts = null, IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) { return new TypstCompiler(path, null, fonts, sysInputs, root, packagePath, includeSystemPackages); } @@ -91,7 +91,7 @@ public static TypstCompiler FromFile(string path, Fonts? fonts = null, Dictionar public static PdfResult CompilePdf( string source, Fonts? fonts = null, - Dictionary? sysInputs = null, + IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true, @@ -115,7 +115,7 @@ public static PdfResult CompilePdf( public static PdfResult CompilePdfFromFile( string path, Fonts? fonts = null, - Dictionary? sysInputs = null, + IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true, @@ -140,7 +140,7 @@ public static SvgResult CompileSvg( string source, float ppi = 144.0f, Fonts? fonts = null, - Dictionary? sysInputs = null, + IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) @@ -164,7 +164,7 @@ public static SvgResult CompileSvgFromFile( string path, float ppi = 144.0f, Fonts? fonts = null, - Dictionary? sysInputs = null, + IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) @@ -188,7 +188,7 @@ public static PngResult CompilePng( string source, float ppi = 144.0f, Fonts? fonts = null, - Dictionary? sysInputs = null, + IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) @@ -212,7 +212,7 @@ public static PngResult CompilePngFromFile( string path, float ppi = 144.0f, Fonts? fonts = null, - Dictionary? sysInputs = null, + IDictionary? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true) @@ -223,7 +223,7 @@ public static PngResult CompilePngFromFile( - private unsafe TypstCompiler(string? inputPath, string? inputSource, Fonts? fonts, Dictionary? sysInputs, string? root, string? packagePath = null, bool includeSystemPackages = true) + private unsafe TypstCompiler(string? inputPath, string? inputSource, Fonts? fonts, IDictionary? sysInputs, string? root, string? packagePath = null, bool includeSystemPackages = true) { fonts ??= new Fonts(); var fontPaths = fonts.FontPaths ?? []; @@ -267,7 +267,7 @@ private unsafe TypstCompiler(string? inputPath, string? inputSource, Fonts? font var packagePathPtr = packagePath != null ? Marshal.StringToCoTaskMemUTF8(packagePath) : IntPtr.Zero; - var sysInputsJson = sysInputs == null ? "{}" : JsonSerializer.Serialize>(sysInputs, sourceGenOptions); + var sysInputsJson = sysInputs == null ? "{}" : JsonSerializer.Serialize>(sysInputs, sourceGenOptions); var sysInputsPtr = Marshal.StringToCoTaskMemUTF8(sysInputsJson); try @@ -548,11 +548,11 @@ public void Compile(string outputFile, string format, float ppi = 144.0f, IEnume /// /// A dictionary of key-value pairs. Values are serialized to JSON and passed to the compiler. /// Thrown if the inputs fail to be set in the native compiler. - public unsafe void SetSysInputs(Dictionary inputs) + public unsafe void SetSysInputs(IDictionary inputs) { if (_disposed) throw new ObjectDisposedException(nameof(TypstCompiler)); - var sysInputsJson = JsonSerializer.Serialize>(inputs, sourceGenOptions); + var sysInputsJson = JsonSerializer.Serialize>(inputs, sourceGenOptions); var sysInputsPtr = Marshal.StringToCoTaskMemUTF8(sysInputsJson); try {