A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4
5namespace UnityEngine.InputSystem.Utilities
6{
7 /// <summary>
8 /// A combination of a name and a value assignment for it.
9 /// </summary>
10 public struct NamedValue : IEquatable<NamedValue>
11 {
12 public const string Separator = ",";
13
14 /// <summary>
15 /// Name of the parameter.
16 /// </summary>
17 public string name { get; set; }
18
19 /// <summary>
20 /// Value of the parameter.
21 /// </summary>
22 public PrimitiveValue value { get; set; }
23
24 public TypeCode type => value.type;
25
26 public NamedValue ConvertTo(TypeCode type)
27 {
28 return new NamedValue
29 {
30 name = name,
31 value = value.ConvertTo(type)
32 };
33 }
34
35 public static NamedValue From<TValue>(string name, TValue value)
36 where TValue : struct
37 {
38 return new NamedValue
39 {
40 name = name,
41 value = PrimitiveValue.From(value)
42 };
43 }
44
45 public override string ToString()
46 {
47 return $"{name}={value}";
48 }
49
50 public bool Equals(NamedValue other)
51 {
52 return string.Equals(name, other.name, StringComparison.InvariantCultureIgnoreCase)
53 && value == other.value;
54 }
55
56 public override bool Equals(object obj)
57 {
58 if (ReferenceEquals(null, obj))
59 return false;
60 return obj is NamedValue parameterValue && Equals(parameterValue);
61 }
62
63 public override int GetHashCode()
64 {
65 unchecked
66 {
67 var hashCode = (name != null ? name.GetHashCode() : 0);
68 hashCode = (hashCode * 397) ^ value.GetHashCode();
69 return hashCode;
70 }
71 }
72
73 public static bool operator==(NamedValue left, NamedValue right)
74 {
75 return left.Equals(right);
76 }
77
78 public static bool operator!=(NamedValue left, NamedValue right)
79 {
80 return !left.Equals(right);
81 }
82
83 public static NamedValue[] ParseMultiple(string parameterString)
84 {
85 if (parameterString == null)
86 throw new ArgumentNullException(nameof(parameterString));
87
88 parameterString = parameterString.Trim();
89 if (string.IsNullOrEmpty(parameterString))
90 return null;
91
92 var parameterCount = parameterString.CountOccurrences(Separator[0]) + 1;
93 var parameters = new NamedValue[parameterCount];
94
95 var index = 0;
96 for (var i = 0; i < parameterCount; ++i)
97 {
98 var parameter = ParseParameter(parameterString, ref index);
99 parameters[i] = parameter;
100 }
101
102 return parameters;
103 }
104
105 public static NamedValue Parse(string str)
106 {
107 var index = 0;
108 return ParseParameter(str, ref index);
109 }
110
111 private static NamedValue ParseParameter(string parameterString, ref int index)
112 {
113 var parameter = new NamedValue();
114 var parameterStringLength = parameterString.Length;
115
116 // Skip whitespace.
117 while (index < parameterStringLength && char.IsWhiteSpace(parameterString[index]))
118 ++index;
119
120 // Parse name.
121 var nameStart = index;
122 while (index < parameterStringLength)
123 {
124 var nextChar = parameterString[index];
125 if (nextChar == '=' || nextChar == Separator[0] || char.IsWhiteSpace(nextChar))
126 break;
127 ++index;
128 }
129 parameter.name = parameterString.Substring(nameStart, index - nameStart);
130
131 // Skip whitespace.
132 while (index < parameterStringLength && char.IsWhiteSpace(parameterString[index]))
133 ++index;
134
135 if (index == parameterStringLength || parameterString[index] != '=')
136 {
137 // No value given so take "=true" as implied.
138 parameter.value = true;
139 }
140 else
141 {
142 ++index; // Skip over '='.
143
144 // Skip whitespace.
145 while (index < parameterStringLength && char.IsWhiteSpace(parameterString[index]))
146 ++index;
147
148 // Parse value.
149 var valueStart = index;
150 while (index < parameterStringLength &&
151 !(parameterString[index] == Separator[0] || char.IsWhiteSpace(parameterString[index])))
152 ++index;
153
154 ////TODO: use Substring struct here so that we don't allocate lots of useless strings
155
156 var value = parameterString.Substring(valueStart, index - valueStart);
157 parameter.value = PrimitiveValue.FromString(value);
158 }
159
160 if (index < parameterStringLength && parameterString[index] == Separator[0])
161 ++index;
162
163 return parameter;
164 }
165
166 public void ApplyToObject(object instance)
167 {
168 if (instance == null)
169 throw new System.ArgumentNullException(nameof(instance));
170
171 var instanceType = instance.GetType();
172
173 ////REVIEW: what about properties?
174 var field = instanceType.GetField(name,
175 BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
176 if (field == null)
177 throw new ArgumentException(
178 $"Cannot find public field '{name}' in '{instanceType.Name}' (while trying to apply parameter)", nameof(instance));
179
180 ////REVIEW: would be awesome to be able to do this without boxing
181 var fieldTypeCode = Type.GetTypeCode(field.FieldType);
182 field.SetValue(instance, value.ConvertTo(fieldTypeCode).ToObject());
183 }
184
185 public static void ApplyAllToObject<TParameterList>(object instance, TParameterList parameters)
186 where TParameterList : IEnumerable<NamedValue>
187 {
188 foreach (var parameter in parameters)
189 parameter.ApplyToObject(instance);
190 }
191 }
192}