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

Sholtee / proxygen / 858

23 Oct 2023 03:28AM UTC coverage: 95.183% (+0.005%) from 95.178%
858

push

appveyor

Sholtee
rewritten Generator class II

2490 of 2616 relevant lines covered (95.18%)

5.61 hits per line

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

97.37
/SRC/Private/Abstractions/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.Runtime.CompilerServices;
10
using System.Threading;
11
using System.Threading.Tasks;
12

13
namespace Solti.Utils.Proxy.Internals
14
{
15
    /// <summary>
16
    /// Base of untyped generators.
17
    /// </summary>
18
    public abstract class Generator : TypeEmitter
19
    {
20
        private sealed class GeneratorContext
21
        {
22
            public Type? GeneratedType { get; set; }
6✔
23

24
            public SemaphoreSlim Lock { get; } = new(1, 1);
6✔
25
        }
26

27
        private static readonly ConcurrentDictionary<object, GeneratorContext> FContextCache = new();
6✔
28
        private static readonly ConcurrentDictionary<object, Func<object?, object>> FActivatorCache = new();
6✔
29

30
        private protected override IEnumerable<UnitSyntaxFactoryBase> CreateChunks(ReferenceCollector referenceCollector)
31
        {
6✔
32
            //
33
            // Don't use Type.GetType() here as it would find the internal implementation in this
34
            // assembly.
35
            //
36

37
            if (typeof(MethodImplAttribute).Assembly.GetType("System.Runtime.CompilerServices.ModuleInitializerAttribute", throwOnError: false) is null)
6✔
38
                yield return new ModuleInitializerSyntaxFactory(OutputType.Unit, referenceCollector);
4✔
39
        }
6✔
40

41
        /// <summary>
42
        /// Creates a new <see cref="Generator"/> instance.
43
        /// </summary>
44
        protected Generator(object id) => Id = id;
6✔
45

46
        internal Task<Type> GetGeneratedTypeAsyncInternal(CancellationToken cancellation)
47
        {
6✔
48
            cancellation.ThrowIfCancellationRequested();
6✔
49

50
            GeneratorContext context = FContextCache.GetOrAdd(Id, static _ => new GeneratorContext());
6✔
51
            if (context.GeneratedType is not null)
6✔
52
                return Task.FromResult(context.GeneratedType);
6✔
53

54
            return Task<Type>.Factory.StartNew
6✔
55
            (
56
                () =>
57
                {
6✔
58
                    context.Lock.Wait(cancellation);
6✔
59
                    try
60
                    {
6✔
61
                        context.GeneratedType ??= Emit(null, WorkingDirectories.Instance.AssemblyCacheDir, cancellation);
6✔
62
                    }
6✔
63
                    finally
64
                    {
6✔
65
                        context.Lock.Release();
6✔
66
                    }
6✔
67
                    return context.GeneratedType;
6✔
68
                },
6✔
69
                cancellation
70
            );
71
        }
6✔
72

73
        internal Task<Func<object?, object>> GetActivatorAsyncInternal(CancellationToken cancellation)
74
        {
6✔
75
            cancellation.ThrowIfCancellationRequested();
6✔
76

77
            return FActivatorCache.TryGetValue(Id, out Func<object?, object> activator)
6✔
78
                ? Task.FromResult(activator)
79
                : Create();
80

81
            async Task<Func<object?, object>> Create()
82
            {
6✔
83
                return FActivatorCache.GetOrAdd(Id, ProxyActivator.Create(await GetGeneratedTypeAsyncInternal(cancellation)));
6✔
84
            }
6✔
85
        }
6✔
86

87
        #region Public
88
        /// <summary>
89
        /// Unique generator id. Generators emitting the same output should have the same id.
90
        /// </summary>
91
        public object Id { get; }
6✔
92

93
        /// <summary>
94
        /// Gets the generated <see cref="Type"/> asynchronously .
95
        /// </summary>
96
        /// <remarks>The returned <see cref="Type"/> is generated only once.</remarks>
97
        public Task<Type> GetGeneratedTypeAsync(CancellationToken cancellation = default) => GetGeneratedTypeAsyncInternal(cancellation);
6✔
98

99
        /// <summary>
100
        /// Gets the generated <see cref="Type"/>.
101
        /// </summary>
102
        /// <remarks>The returned <see cref="Type"/> is generated only once.</remarks>
103
        public Type GetGeneratedType() => GetGeneratedTypeAsync()
6✔
104
            .GetAwaiter()
105
            .GetResult();
106

107
        /// <summary>
108
        /// Creates an instance of the generated type.
109
        /// </summary>
110
        /// <param name="tuple">A <see cref="Tuple"/> containing the constructor parameters or null if you want to invoke the parameterless constructor.</param>
111
        /// <param name="cancellation">Token to cancel the operation.</param>
112
        /// <returns>The just activated instance.</returns>
113
        #if NETSTANDARD2_1_OR_GREATER
114
        public async Task<object> ActivateAsync(ITuple? tuple, CancellationToken cancellation = default) =>
115
        #else
116
        public async Task<object> ActivateAsync(object? tuple, CancellationToken cancellation = default) =>
117
        #endif
118
            (await GetActivatorAsyncInternal(cancellation)).Invoke(tuple);
6✔
119

120
        /// <summary>
121
        /// Creates an instance of the generated type.
122
        /// </summary>
123
        /// <param name="tuple">A <see cref="Tuple"/> containing the constructor parameters or null if you want to invoke the parameterless constructor.</param>
124
        /// <returns>The just activated instance.</returns>
125
        #if NETSTANDARD2_1_OR_GREATER
126
        public object Activate(ITuple? tuple) =>
127
        #else
128
        public object Activate(object? tuple) =>
129
        #endif
130
            GetActivatorAsyncInternal(default)
×
131
            .GetAwaiter()
132
            .GetResult()
133
            .Invoke(tuple);
134
        #endregion
135
    }
136
}
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