|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +// Copyright AppMotor Framework (https://github.com/skrysm/AppMotor) |
| 3 | + |
| 4 | +using System.Diagnostics.CodeAnalysis; |
| 5 | +using System.Reflection; |
| 6 | +using System.Text; |
| 7 | + |
| 8 | +using AppMotor.CoreKit.Exceptions; |
| 9 | +using AppMotor.CoreKit.Extensions; |
| 10 | + |
| 11 | +using JetBrains.Annotations; |
| 12 | + |
| 13 | +namespace AppMotor.CoreKit.Utils; |
| 14 | + |
| 15 | +/// <summary> |
| 16 | +/// Provides an "accessor" to an embedded resource of an assembly. |
| 17 | +/// </summary> |
| 18 | +[SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "No really a data class")] |
| 19 | +public readonly struct EmbeddedResource |
| 20 | +{ |
| 21 | + private readonly Assembly _assembly; |
| 22 | + |
| 23 | + private readonly string _resourceName; |
| 24 | + |
| 25 | + /// <summary> |
| 26 | + /// Constructor for existing resource. |
| 27 | + /// </summary> |
| 28 | + internal EmbeddedResource(Assembly assembly, string resourceName) |
| 29 | + { |
| 30 | + Validate.ArgumentWithName(nameof(assembly)).IsNotNull(assembly); |
| 31 | + Validate.ArgumentWithName(nameof(resourceName)).IsNotNullOrWhiteSpace(resourceName); |
| 32 | + |
| 33 | + this._assembly = assembly; |
| 34 | + this._resourceName = resourceName; |
| 35 | + } |
| 36 | + |
| 37 | + /// <summary> |
| 38 | + /// Constructs the resource name from the type's namespace and the resource name. |
| 39 | + /// </summary> |
| 40 | + /// <param name="type">The type whose namespace is used to scope the <paramref name="resourceName"/>.</param> |
| 41 | + /// <param name="resourceName">The resource name (case-sensitive).</param> |
| 42 | + [MustUseReturnValue] |
| 43 | + public static string ConstructResourceName(Type type, string resourceName) |
| 44 | + { |
| 45 | + var nameSpace = type.Namespace; |
| 46 | + |
| 47 | + char c = Type.Delimiter; |
| 48 | + |
| 49 | + return string.Concat(nameSpace, new ReadOnlySpan<char>(in c), resourceName); |
| 50 | + } |
| 51 | + |
| 52 | + /// <summary> |
| 53 | + /// Returns a <see cref="Stream"/> for this resource. |
| 54 | + /// </summary> |
| 55 | + [MustUseReturnValue, MustDisposeResource] |
| 56 | + public Stream AsStream() |
| 57 | + { |
| 58 | + // NOTE: We throw an UnexpectedBehaviorException() here because the premise of this type is that the resource exists. |
| 59 | + return this._assembly.GetManifestResourceStream(this._resourceName) |
| 60 | + ?? throw new UnexpectedBehaviorException($"The embedded resource '{this._resourceName}' doesn't exist in assembly '{this._assembly.GetSimpleName()}'."); |
| 61 | + } |
| 62 | + |
| 63 | + /// <summary> |
| 64 | + /// Returns this resource as byte array. |
| 65 | + /// </summary> |
| 66 | + /// <returns></returns> |
| 67 | + [MustUseReturnValue] |
| 68 | + public byte[] AsBytes() |
| 69 | + { |
| 70 | + using var stream = AsStream(); |
| 71 | + return stream.ReadAsBytes(); |
| 72 | + } |
| 73 | + |
| 74 | + /// <summary> |
| 75 | + /// Returns this resource as string. |
| 76 | + /// </summary> |
| 77 | + [MustUseReturnValue] |
| 78 | + public string AsString(Encoding encoding) |
| 79 | + { |
| 80 | + using var stream = AsStream(); |
| 81 | + return stream.ReadAsString(encoding); |
| 82 | + } |
| 83 | + |
| 84 | + /// <summary> |
| 85 | + /// Returns this resource as lines. |
| 86 | + /// </summary> |
| 87 | + [MustUseReturnValue] |
| 88 | + public IEnumerable<string> AsLines(Encoding encoding) |
| 89 | + { |
| 90 | + // NOTE: This is generally safe as this line will only be called when "IEnumerable<string>.GetEnumerator()" is called - |
| 91 | + // NOT when this method is called. (It's the C# iterator magic.) |
| 92 | + using var stream = AsStream(); |
| 93 | + |
| 94 | + // IMPORTANT: We must NOT return the result of "ReadAsLine()" directly here because |
| 95 | + // we need to make sure the stream is only disposed after all (required) lines have |
| 96 | + // been read. |
| 97 | + foreach (var line in stream.ReadAsLines(encoding)) |
| 98 | + { |
| 99 | + yield return line; |
| 100 | + } |
| 101 | + } |
| 102 | +} |
0 commit comments