• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

me-viper / OpaDotNet.Compilation / 6942841257

21 Nov 2023 09:53AM UTC coverage: 88.266%. Remained the same
6942841257

push

github

me-viper
chore: Update CHANGELOG

180 of 220 branches covered (0.0%)

Branch coverage included in aggregate %.

670 of 743 relevant lines covered (90.17%)

533.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.48
/src/OpaDotNet.Compilation.Interop/Interop.cs
1
using System.Runtime.InteropServices;
2

3
using Microsoft.Extensions.Logging;
4
using Microsoft.Extensions.Logging.Abstractions;
5

6
using OpaDotNet.Compilation.Abstractions;
7

8
namespace OpaDotNet.Compilation.Interop;
9

10
internal static class Interop
11
{
12
    private const string Lib = "Opa.Interop";
13

14
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
15
    public struct OpaVersion
16
    {
17
        public string LibVersion;
18

19
        public string GoVersion;
20

21
        public string? Commit;
22

23
        public string Platform;
24
    }
25

26
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
27
    private struct OpaBytesBuildParams
28
    {
29
        public nint Bytes;
30

31
        public int BytesLen;
32

33
        public OpaBuildParams Params;
34
    }
35

36
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
37
    private struct OpaFsBuildParams
38
    {
39
        public string Source;
40

41
        public OpaBuildParams Params;
42
    }
43

44
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
45
    private struct OpaBuildParams
46
    {
47
        public string Target;
48

49
        public string? CapabilitiesJson;
50

51
        public string? CapabilitiesVersion;
52

53
        [MarshalAs(UnmanagedType.I1)]
54
        public bool BundleMode;
55

56
        public nint Entrypoints;
57

58
        public int EntrypointsLen;
59

60
        [MarshalAs(UnmanagedType.I1)]
61
        public bool Debug;
62

63
        public int OptimizationLevel;
64

65
        [MarshalAs(UnmanagedType.I1)]
66
        public bool PruneUnused;
67

68
        public string? TempDir;
69

70
        public string? Revision;
71

72
        public nint Ignore;
73

74
        public int IgnoreLen;
75
    }
76

77
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
78
    private struct OpaBuildResult
79
    {
80
        public nint Result;
81

82
        public int ResultLen;
83

84
        public string? Errors;
85

86
        public string? Log;
87
    }
88

89
    [DllImport(Lib, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
90
    public static extern nint OpaGetVersion();
91

92
    [DllImport(Lib, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
93
    private static extern int OpaBuildFromFs(
94
        [In] ref OpaFsBuildParams buildParams,
95
        out nint result);
96

97
    [DllImport(Lib, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
98
    private static extern int OpaBuildFromBytes(
99
        [In] ref OpaBytesBuildParams buildParams,
100
        out nint result);
101

102
    [DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
103
    private static extern void OpaFree(nint buildResult);
104

105
    private static Stream Compile(
106
        Func<OpaBuildParams, (int, nint)> compile,
107
        bool isBundle,
108
        RegoCompilerOptions options,
109
        IEnumerable<string>? entrypoints,
110
        Stream? capabilitiesJson,
111
        ILogger? logger)
112
    {
72✔
113
        ArgumentNullException.ThrowIfNull(compile);
72✔
114
        ArgumentNullException.ThrowIfNull(options);
72✔
115

116
        logger ??= NullLogger.Instance;
72!
117

118
        var pEntrypoints = nint.Zero;
72✔
119
        var entrypointsList = Array.Empty<nint>();
72✔
120

121
        var pIgnore = nint.Zero;
72✔
122
        var ignoreList = Array.Empty<nint>();
72✔
123

124
        try
125
        {
72✔
126
            string? caps = null;
72✔
127

128
            if (capabilitiesJson != null)
72✔
129
            {
12✔
130
                using var sr = new StreamReader(capabilitiesJson);
12✔
131
                caps = sr.ReadToEnd();
12✔
132
            }
12✔
133

134
            var buildParams = new OpaBuildParams
72✔
135
            {
72✔
136
                CapabilitiesVersion = options.CapabilitiesVersion,
72✔
137
                CapabilitiesJson = caps,
72✔
138
                BundleMode = isBundle,
72✔
139
                Target = "wasm",
72✔
140
                Debug = options.Debug,
72✔
141
                PruneUnused = options.PruneUnused,
72✔
142
                TempDir = Path.GetFullPath(options.OutputPath ?? "./"),
72✔
143
            };
72✔
144

145
            if (entrypoints != null)
72✔
146
            {
60✔
147
                var ep = entrypoints as string[] ?? entrypoints.ToArray();
60✔
148
                pEntrypoints = Marshal.AllocCoTaskMem(ep.Length * nint.Size);
60✔
149
                entrypointsList = new nint[ep.Length];
60✔
150

151
                for (var i = 0; i < ep.Length; i++)
256✔
152
                    entrypointsList[i] = Marshal.StringToCoTaskMemAnsi(ep[i]);
68✔
153

154
                Marshal.Copy(entrypointsList, 0, pEntrypoints, ep.Length);
60✔
155

156
                buildParams.Entrypoints = pEntrypoints;
60✔
157
                buildParams.EntrypointsLen = ep.Length;
60✔
158
            }
60✔
159

160
            if (options.Ignore is { Count: > 0 })
72!
161
            {
6✔
162
                pIgnore = Marshal.AllocCoTaskMem(options.Ignore.Count * nint.Size);
6✔
163
                ignoreList = new nint[options.Ignore.Count];
6✔
164

165
                var i = 0;
6✔
166

167
                foreach (var ign in options.Ignore)
34✔
168
                    ignoreList[i++] = Marshal.StringToCoTaskMemAnsi(ign);
8✔
169

170
                Marshal.Copy(ignoreList, 0, pIgnore, options.Ignore.Count);
6✔
171

172
                buildParams.Ignore = pIgnore;
6✔
173
                buildParams.IgnoreLen = options.Ignore.Count;
6✔
174
            }
6✔
175

176
            var bundle = nint.Zero;
72✔
177

178
            try
179
            {
72✔
180
                (var result, bundle) = compile(buildParams);
72✔
181

182
                if (bundle == nint.Zero)
72!
183
                    throw new RegoCompilationException("Compilation failed");
×
184

185
                var resultBundle = Marshal.PtrToStructure<OpaBuildResult>(bundle);
72✔
186

187
                if (!string.IsNullOrWhiteSpace(resultBundle.Log))
72✔
188
                    logger.LogDebug("{BuildLog}", resultBundle.Log);
44✔
189

190
                if (!string.IsNullOrWhiteSpace(resultBundle.Errors))
72✔
191
                    throw new RegoCompilationException(resultBundle.Errors);
8✔
192

193
                if (result != 0)
64!
194
                    throw new RegoCompilationException($"Compilation error {result}");
×
195

196
                if (resultBundle.ResultLen == 0 || resultBundle.Result == nint.Zero)
64!
197
                    throw new RegoCompilationException("Bad result");
×
198

199
                var bundleBytes = new byte[resultBundle.ResultLen];
64✔
200
                Marshal.Copy(resultBundle.Result, bundleBytes, 0, resultBundle.ResultLen);
64✔
201

202
                return new MemoryStream(bundleBytes);
64✔
203
            }
204
            finally
205
            {
72✔
206
                if (bundle != nint.Zero)
72✔
207
                    OpaFree(bundle);
72✔
208
            }
72✔
209
        }
210
        finally
211
        {
72✔
212
            if (pEntrypoints != nint.Zero)
72✔
213
            {
60✔
214
                foreach (var p in entrypointsList)
316✔
215
                    Marshal.FreeCoTaskMem(p);
68✔
216

217
                Marshal.FreeCoTaskMem(pEntrypoints);
60✔
218
            }
60✔
219

220
            if (pIgnore != nint.Zero)
72✔
221
            {
6✔
222
                foreach (var p in ignoreList)
34✔
223
                    Marshal.FreeCoTaskMem(p);
8✔
224

225
                Marshal.FreeCoTaskMem(pIgnore);
6✔
226
            }
6✔
227
        }
72✔
228
    }
64✔
229

230
    public static Stream Compile(
231
        string source,
232
        bool isBundle,
233
        RegoCompilerOptions options,
234
        IEnumerable<string>? entrypoints,
235
        Stream? capabilitiesJson,
236
        ILogger? logger)
237
    {
50✔
238
        ArgumentException.ThrowIfNullOrEmpty(source);
50✔
239
        ArgumentNullException.ThrowIfNull(options);
50✔
240

241
        static (int, nint) CompileFunc(string source, OpaBuildParams buildParams)
242
        {
50✔
243
            var fsBuildParams = new OpaFsBuildParams
50✔
244
            {
50✔
245
                Source = source,
50✔
246
                Params = buildParams,
50✔
247
            };
50✔
248

249
            var result = OpaBuildFromFs(ref fsBuildParams, out var bundle);
50✔
250
            return (result, bundle);
50✔
251
        }
50✔
252

253
        return Compile(p => CompileFunc(source, p), isBundle, options, entrypoints, capabilitiesJson, logger);
100✔
254
    }
46✔
255

256
    public static Stream Compile(
257
        Stream source,
258
        bool isBundle,
259
        RegoCompilerOptions options,
260
        IEnumerable<string>? entrypoints,
261
        Stream? capabilitiesJson,
262
        ILogger? logger)
263
    {
22✔
264
        ArgumentNullException.ThrowIfNull(source);
22✔
265
        ArgumentNullException.ThrowIfNull(options);
22✔
266

267
        static (int, nint) CompileFunc(Stream source, OpaBuildParams buildParams)
268
        {
22✔
269
            var bytes = nint.Zero;
22✔
270

271
            try
272
            {
22✔
273
                var len = (int)source.Length;
22✔
274
                bytes = Marshal.AllocCoTaskMem(len);
22✔
275

276
                // It's possible to do this without unsafe code but it requires creating intermediate array
277
                // and extra copying. And not that this option would be safer.
278
                unsafe
279
                {
22✔
280
                    var b = new Span<byte>(bytes.ToPointer(), len);
22✔
281
                    _ = source.Read(b);
22✔
282
                }
22✔
283

284
                var bytesBuildParams = new OpaBytesBuildParams
22✔
285
                {
22✔
286
                    Bytes = bytes,
22✔
287
                    BytesLen = len,
22✔
288
                    Params = buildParams,
22✔
289
                };
22✔
290

291
                var result = OpaBuildFromBytes(ref bytesBuildParams, out var bundle);
22✔
292
                return (result, bundle);
22✔
293
            }
294
            finally
295
            {
22✔
296
                Marshal.FreeCoTaskMem(bytes);
22✔
297
            }
22✔
298
        }
22✔
299

300
        return Compile(p => CompileFunc(source, p), isBundle, options, entrypoints, capabilitiesJson, logger);
44✔
301
    }
18✔
302
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc