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

Sholtee / proxygen / 1077

15 Jun 2025 07:21AM UTC coverage: 92.853%. Remained the same
1077

push

appveyor

Sholtee
document internal classes VII

4807 of 5177 relevant lines covered (92.85%)

0.93 hits per line

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

97.14
/SRC/Private/Generators/Generator.cs
1
/********************************************************************************
2
* Generator.cs                                                                  *
3
*                                                                               *
4
* Author: Denes Solti                                                           *
5
********************************************************************************/
6
using System;
7
using System.Collections.Generic;
8
using System.Collections.Concurrent;
9
using System.Diagnostics;
10
using System.Linq;
11
using System.Runtime.CompilerServices;
12
using System.Threading;
13
using System.Threading.Tasks;
14

15
using Tuple =
16
    #if NETSTANDARD2_1_OR_GREATER
17
    System.Runtime.CompilerServices.ITuple;
18
    #else
19
    object;
20
    #endif
21

22
namespace Solti.Utils.Proxy.Internals
23
{
24
    /// <summary>
25
    /// Base of untyped generators.
26
    /// </summary>
27
    public abstract class Generator(object id) : TypeEmitter
1✔
28
    {
29
        #region Private
30
        private sealed class ContextWrapper
31
        {
32
            public TypeContext? Context { get; set; }
1✔
33

34
            public SemaphoreSlim Lock { get; } = new(1, 1);
1✔
35
        }
36

37
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
38
        private static readonly ConcurrentDictionary<object, ContextWrapper> FContextCache = new();
1✔
39

40
        /// <inheritdoc/>
41
        private protected override IEnumerable<UnitSyntaxFactoryBase> CreateChunks(SyntaxFactoryContext context)
42
        {
1✔
43
            //
44
            // Don't use Type.GetType() here as it would find the internal implementation in this
45
            // assembly.
46
            //
47

48
            if (typeof(MethodImplAttribute).Assembly.GetType("System.Runtime.CompilerServices.ModuleInitializerAttribute", throwOnError: false) is null)
1✔
49
                yield return new ModuleInitializerSyntaxFactory(context);
×
50
        }
1✔
51

52
        /// <summary>
53
        /// Wraps the <see cref="TypeEmitter.EmitAsync(CancellationToken)"/> function to make it thread safe. Also implements singleton pattern using the <see cref="Id"/> property.
54
        /// </summary>
55
        private async Task<TypeContext> GetContextAsync(CancellationToken cancellation)
56
        {
1✔
57
            cancellation.ThrowIfCancellationRequested();
1✔
58

59
            ContextWrapper context = FContextCache.GetOrAdd(Id, static _ => new ContextWrapper());
1✔
60
            if (context.Context is not null)
1✔
61
                return context.Context;
1✔
62

63
            await context.Lock.WaitAsync(cancellation);
1✔
64

65
            try
66
            {
1✔
67
                context.Context ??= await EmitAsync(cancellation);
1✔
68
            }
1✔
69
            finally
70
            {
1✔
71
                context.Lock.Release();
1✔
72
            }
1✔
73

74
            return context.Context;
1✔
75
        }
1✔
76
        #endregion
77

78
        #region Protected
79
        /// <summary>
80
        /// Creates unique generator ids. 
81
        /// </summary>
82
        protected static string GenerateId(string prefix, params IEnumerable<Type> types) =>
83
            $"{prefix}:{types.Select(MetadataTypeInfo.CreateFrom).GetMD5HashCode()}";
1✔
84

85
        /// <summary>
86
        /// Creates an instance of the generated type.
87
        /// </summary>
88
        /// <param name="tuple">A <see cref="Tuple"/> containing the constructor parameters or null if you want to invoke the parameterless constructor.</param>
89
        /// <param name="cancellation">Token to cancel the operation.</param>
90
        /// <returns>The just activated instance.</returns>
91
        protected async Task<object> ActivateAsync(Tuple? tuple, CancellationToken cancellation)
92
        {
1✔
93
            TypeContext context = await GetContextAsync(cancellation);
1✔
94
            return context.Activator(tuple!);
1✔
95
        }
1✔
96
        #endregion
97

98
        #region Public
99
        /// <summary>
100
        /// Unique generator id. Generators emitting the same output should have the same id.
101
        /// </summary>
102
        public object Id { get; } = id ?? throw new ArgumentNullException(nameof(id));
1✔
103

104
        /// <summary>
105
        /// Gets the generated <see cref="Type"/> asynchronously .
106
        /// </summary>
107
        /// <remarks>The returned <see cref="Type"/> is generated only once.</remarks>
108
        public async Task<Type> GetGeneratedTypeAsync(CancellationToken cancellation = default)
109
        {
1✔
110
            TypeContext context = await GetContextAsync(cancellation);
1✔
111
            return context.Type;
1✔
112
        }
1✔
113

114
        /// <summary>
115
        /// Gets the generated <see cref="Type"/>.
116
        /// </summary>
117
        /// <remarks>The returned <see cref="Type"/> is generated only once.</remarks>
118
        public Type GetGeneratedType() => GetGeneratedTypeAsync()
1✔
119
            .GetAwaiter()
1✔
120
            .GetResult();
1✔
121
        #endregion
122
    }
123
}
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

© 2025 Coveralls, Inc