123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- 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);
- }
- }
- }
|