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