1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using System.Reflection;
12 
13 namespace Antmicro.Renode.Core
14 {
15     public class ObjectCreator
16     {
ObjectCreator()17         static ObjectCreator()
18         {
19             Instance = new ObjectCreator();
20         }
21 
22         public static ObjectCreator Instance { get; private set; }
23 
OpenContext()24         public Context OpenContext()
25         {
26             var context = new Context(this);
27             contexts.Push(context);
28             return context;
29         }
30 
Spawn(Type type, Func<ParameterInfo, object> argumentResolver = null)31         public object Spawn(Type type, Func<ParameterInfo, object> argumentResolver = null)
32         {
33             foreach(var constructor in type.GetConstructors())
34             {
35                 var @params = constructor.GetParameters();
36                 var args = new object[@params.Length];
37                 var success = true;
38                 for(int i = 0; i < args.Length; i++)
39                 {
40                     var surrogate = GetSurrogate(@params[i].ParameterType);
41                     if(surrogate == null)
42                     {
43                         if(argumentResolver != null)
44                         {
45                             surrogate = argumentResolver(@params[i]);
46                         }
47                     }
48                     if(surrogate == null)
49                     {
50                         success = false;
51                         break;
52                     }
53 
54                     args[i] = surrogate;
55                 }
56 
57                 // try next constructor
58                 if(!success)
59                 {
60                     continue;
61                 }
62 
63                 return Activator.CreateInstance(type, args);
64             }
65 
66             // if no constructor was matched, throw exception
67             throw new ArgumentException(string.Format("Couldn't spawn object of type: {0}\nAvailable surrogate types are:\n{1}", type.FullName,
68                 string.Join("\n", contexts.SelectMany(x => x.Types).Distinct().Select(x => x.FullName))));
69         }
70 
GetSurrogate()71         public T GetSurrogate<T>()
72         {
73             return (T)GetSurrogate(typeof(T));
74         }
75 
GetSurrogate(Type type)76         public object GetSurrogate(Type type)
77         {
78             return contexts.Select(x => x.GetSurrogate(type)).FirstOrDefault(x => x != null);
79         }
80 
GetSurrogate(string typeName)81         public object GetSurrogate(string typeName)
82         {
83             return contexts.Select(x => x.GetSurrogate(typeName)).FirstOrDefault(x => x != null);
84         }
85 
ObjectCreator()86         protected ObjectCreator()
87         {
88             contexts = new Stack<Context>();
89         }
90 
CloseContext(Context context)91         private void CloseContext(Context context)
92         {
93             if(context != contexts.Peek())
94             {
95                 throw new ArgumentException();
96             }
97 
98             contexts.Pop();
99         }
100 
101         private readonly Stack<Context> contexts;
102 
103         public class Context : IDisposable
104         {
Context(ObjectCreator creator)105             public Context(ObjectCreator creator)
106             {
107                 objectCreator = creator;
108                 surrogates = new Dictionary<Type, object>();
109             }
110 
RegisterSurrogate(Type type, object obj)111             public void RegisterSurrogate(Type type, object obj)
112             {
113                 surrogates.Add(type, obj);
114             }
115 
GetSurrogate(Type type)116             public object GetSurrogate(Type type)
117             {
118                 object result;
119                 surrogates.TryGetValue(type, out result);
120                 return result;
121             }
122 
GetSurrogate(string typeName)123             public object GetSurrogate(string typeName)
124             {
125                 return surrogates.FirstOrDefault(x => x.Key.FullName.Contains(typeName)).Value;
126             }
127 
Close()128             public void Close()
129             {
130                 objectCreator.CloseContext(this);
131             }
132 
Dispose()133             public void Dispose()
134             {
135                 Close();
136             }
137 
138             public IEnumerable<Type> Types { get { return surrogates.Keys; } }
139 
140             private readonly ObjectCreator objectCreator;
141             private readonly Dictionary<Type, object> surrogates;
142         }
143     }
144 }
145 
146