A game about forced loneliness, made by TACStudios
at master 192 lines 6.4 kB view raw
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}