123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089 |
- using System;
- using System.Globalization;
- using System.Runtime.InteropServices;
- using Unity.Collections.LowLevel.Unsafe;
-
- ////REVIEW: add Vector2 and Vector3 as primitive value types?
-
- namespace UnityEngine.InputSystem.Utilities
- {
- /// <summary>
- /// A union holding a primitive value.
- /// </summary>
- /// <remarks>
- /// This structure is used for storing things such as default states for controls
- /// (see <see cref="Layouts.InputControlLayout.ControlItem.defaultState"/>). It can
- /// store one value of any primitive, non-reference C# type (bool, char, int, float, etc).
- /// </remarks>
- [StructLayout(LayoutKind.Explicit)]
- public struct PrimitiveValue : IEquatable<PrimitiveValue>, IConvertible
- {
- [FieldOffset(0)] private TypeCode m_Type;
- [FieldOffset(4)] private bool m_BoolValue;
- [FieldOffset(4)] private char m_CharValue;
- [FieldOffset(4)] private byte m_ByteValue;
- [FieldOffset(4)] private sbyte m_SByteValue;
- [FieldOffset(4)] private short m_ShortValue;
- [FieldOffset(4)] private ushort m_UShortValue;
- [FieldOffset(4)] private int m_IntValue;
- [FieldOffset(4)] private uint m_UIntValue;
- [FieldOffset(4)] private long m_LongValue;
- [FieldOffset(4)] private ulong m_ULongValue;
- [FieldOffset(4)] private float m_FloatValue;
- [FieldOffset(4)] private double m_DoubleValue;
-
- internal unsafe byte* valuePtr => (byte*)UnsafeUtility.AddressOf(ref this) + 4;
-
- /// <summary>
- /// Type of value stored in the struct. <see cref="TypeCode.Empty"/>
- /// if the struct does not hold a value (i.e. has been default-initialized).
- /// </summary>
- /// <value>Type of value stored in the struct.</value>
- public TypeCode type => m_Type;
-
- /// <summary>
- /// If true, the struct does not contain a primitive value (i.e. has <see cref="type"/>
- /// <see cref="TypeCode.Empty"/>).
- /// </summary>
- /// <value>Whether the struct is holding a value or not.</value>
- public bool isEmpty => type == TypeCode.Empty;
-
- /// <summary>
- /// Create a PrimitiveValue holding a bool.
- /// </summary>
- /// <param name="value">A boolean value.</param>
- public PrimitiveValue(bool value)
- : this()
- {
- m_Type = TypeCode.Boolean;
- m_BoolValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a character.
- /// </summary>
- /// <param name="value">A character.</param>
- public PrimitiveValue(char value)
- : this()
- {
- m_Type = TypeCode.Char;
- m_CharValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a byte.
- /// </summary>
- /// <param name="value">A byte value.</param>
- public PrimitiveValue(byte value)
- : this()
- {
- m_Type = TypeCode.Byte;
- m_ByteValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a signed byte.
- /// </summary>
- /// <param name="value">A signed byte value.</param>
- public PrimitiveValue(sbyte value)
- : this()
- {
- m_Type = TypeCode.SByte;
- m_SByteValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a short.
- /// </summary>
- /// <param name="value">A short value.</param>
- public PrimitiveValue(short value)
- : this()
- {
- m_Type = TypeCode.Int16;
- m_ShortValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding an unsigned short.
- /// </summary>
- /// <param name="value">An unsigned short value.</param>
- public PrimitiveValue(ushort value)
- : this()
- {
- m_Type = TypeCode.UInt16;
- m_UShortValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding an int.
- /// </summary>
- /// <param name="value">An int value.</param>
- public PrimitiveValue(int value)
- : this()
- {
- m_Type = TypeCode.Int32;
- m_IntValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding an unsigned int.
- /// </summary>
- /// <param name="value">An unsigned int value.</param>
- public PrimitiveValue(uint value)
- : this()
- {
- m_Type = TypeCode.UInt32;
- m_UIntValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a long.
- /// </summary>
- /// <param name="value">A long value.</param>
- public PrimitiveValue(long value)
- : this()
- {
- m_Type = TypeCode.Int64;
- m_LongValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a ulong.
- /// </summary>
- /// <param name="value">An unsigned long value.</param>
- public PrimitiveValue(ulong value)
- : this()
- {
- m_Type = TypeCode.UInt64;
- m_ULongValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a float.
- /// </summary>
- /// <param name="value">A float value.</param>
- public PrimitiveValue(float value)
- : this()
- {
- m_Type = TypeCode.Single;
- m_FloatValue = value;
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a double.
- /// </summary>
- /// <param name="value">A double value.</param>
- public PrimitiveValue(double value)
- : this()
- {
- m_Type = TypeCode.Double;
- m_DoubleValue = value;
- }
-
- /// <summary>
- /// Convert to another type of value.
- /// </summary>
- /// <param name="type">Type of value to convert to.</param>
- /// <returns>The converted value.</returns>
- /// <exception cref="ArgumentException">There is no conversion from the
- /// PrimitiveValue's current <see cref="PrimitiveValue.type"/> to
- /// <paramref name="type"/>.</exception>
- /// <remarks>
- /// This method simply calls the other conversion methods (<see cref="ToBoolean"/>,
- /// <see cref="ToChar"/>, etc) based on the current type of value. <c>ArgumentException</c>
- /// is thrown if there is no conversion from the current to the requested type.
- ///
- /// Every value can be converted to <c>TypeCode.Empty</c>.
- /// </remarks>
- /// <seealso cref="ToBoolean"/>
- /// <seealso cref="ToChar"/>
- /// <seealso cref="ToByte"/>
- /// <seealso cref="ToSByte"/>
- /// <seealso cref="ToInt16"/>
- /// <seealso cref="ToInt32"/>
- /// <seealso cref="ToInt64"/>
- /// <seealso cref="ToUInt16"/>
- /// <seealso cref="ToUInt32"/>
- /// <seealso cref="ToUInt64"/>
- /// <seealso cref="ToSingle"/>
- /// <seealso cref="ToDouble"/>
- public PrimitiveValue ConvertTo(TypeCode type)
- {
- switch (type)
- {
- case TypeCode.Boolean: return ToBoolean();
- case TypeCode.Char: return ToChar();
- case TypeCode.Byte: return ToByte();
- case TypeCode.SByte: return ToSByte();
- case TypeCode.Int16: return ToInt16();
- case TypeCode.Int32: return ToInt32();
- case TypeCode.Int64: return ToInt64();
- case TypeCode.UInt16: return ToInt16();
- case TypeCode.UInt32: return ToInt32();
- case TypeCode.UInt64: return ToUInt64();
- case TypeCode.Single: return ToSingle();
- case TypeCode.Double: return ToDouble();
- case TypeCode.Empty: return new PrimitiveValue();
- }
-
- throw new ArgumentException($"Don't know how to convert PrimitiveValue to '{type}'", nameof(type));
- }
-
- /// <summary>
- /// Compare this value to <paramref name="other"/>.
- /// </summary>
- /// <param name="other">Another value.</param>
- /// <returns>True if the two values are equal.</returns>
- /// <remarks>
- /// Equality is based on type and contents. The types of both values
- /// must be identical and the memory contents of each value must be
- /// bit-wise identical (i.e. things such as floating-point epsilons
- /// are not taken into account).
- /// </remarks>
- public unsafe bool Equals(PrimitiveValue other)
- {
- if (m_Type != other.m_Type)
- return false;
-
- var thisValuePtr = UnsafeUtility.AddressOf(ref m_DoubleValue);
- var otherValuePtr = UnsafeUtility.AddressOf(ref other.m_DoubleValue);
-
- return UnsafeUtility.MemCmp(thisValuePtr, otherValuePtr, sizeof(double)) == 0;
- }
-
- /// <summary>
- /// Compare this value to the value of <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">Either another PrimitiveValue or a boxed primitive
- /// value such as a byte, bool, etc.</param>
- /// <returns>True if the two values are equal.</returns>
- /// <remarks>
- /// If <paramref name="obj"/> is a boxed primitive value, it is automatically
- /// converted to a PrimitiveValue.
- /// </remarks>
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj))
- return false;
- if (obj is PrimitiveValue value)
- return Equals(value);
- if (obj is bool || obj is char || obj is byte || obj is sbyte || obj is short
- || obj is ushort || obj is int || obj is uint || obj is long || obj is ulong
- || obj is float || obj is double)
- return Equals(FromObject(obj));
- return false;
- }
-
- /// <summary>
- /// Compare two PrimitiveValues for equality.
- /// </summary>
- /// <param name="left">First value.</param>
- /// <param name="right">Second value.</param>
- /// <returns>True if the two values are equal.</returns>
- /// <seealso cref="Equals(PrimitiveValue)"/>
- public static bool operator==(PrimitiveValue left, PrimitiveValue right)
- {
- return left.Equals(right);
- }
-
- /// <summary>
- /// Compare two PrimitiveValues for inequality.
- /// </summary>
- /// <param name="left">First value.</param>
- /// <param name="right">Second value.</param>
- /// <returns>True if the two values are not equal.</returns>
- /// <seealso cref="Equals(PrimitiveValue)"/>
- public static bool operator!=(PrimitiveValue left, PrimitiveValue right)
- {
- return !left.Equals(right);
- }
-
- /// <summary>
- /// Compute a hash code for the value.
- /// </summary>
- /// <returns>A hash code.</returns>
- public override unsafe int GetHashCode()
- {
- unchecked
- {
- fixed(double* valuePtr = &m_DoubleValue)
- {
- var hashCode = m_Type.GetHashCode();
- hashCode = (hashCode * 397) ^ valuePtr->GetHashCode();
- return hashCode;
- }
- }
- }
-
- /// <summary>
- /// Return a string representation of the value.
- /// </summary>
- /// <returns>A string representation of the value.</returns>
- /// <remarks>
- /// String versions of PrimitiveValues are always culture invariant. This means that
- /// floating-point values, for example, will <em>not</em> the decimal separator of
- /// the current culture.
- /// </remarks>
- /// <seealso cref="FromString"/>
- public override string ToString()
- {
- switch (type)
- {
- case TypeCode.Boolean:
- // Default ToString() uses "False" and "True". We want lowercase to match C# literals.
- return m_BoolValue ? "true" : "false";
- case TypeCode.Char:
- return $"'{m_CharValue.ToString()}'";
- case TypeCode.Byte:
- return m_ByteValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.SByte:
- return m_SByteValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.Int16:
- return m_ShortValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.UInt16:
- return m_UShortValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.Int32:
- return m_IntValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.UInt32:
- return m_UIntValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.Int64:
- return m_LongValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.UInt64:
- return m_ULongValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.Single:
- return m_FloatValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- case TypeCode.Double:
- return m_DoubleValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
- default:
- return string.Empty;
- }
- }
-
- /// <summary>
- /// Parse the given string into a PrimitiveValue.
- /// </summary>
- /// <param name="value">A string containing a value.</param>
- /// <returns>The PrimitiveValue parsed from the string.</returns>
- /// <remarks>
- /// Integers are parsed as longs. Floating-point numbers are parsed as doubles.
- /// Hexadecimal notation is supported for integers.
- /// </remarks>
- /// <seealso cref="ToString()"/>
- public static PrimitiveValue FromString(string value)
- {
- if (string.IsNullOrEmpty(value))
- return new PrimitiveValue();
-
- // Bool.
- if (value.Equals("true", StringComparison.InvariantCultureIgnoreCase))
- return new PrimitiveValue(true);
- if (value.Equals("false", StringComparison.InvariantCultureIgnoreCase))
- return new PrimitiveValue(false);
-
- // Double.
- if (value.Contains('.') || value.Contains("e") || value.Contains("E") ||
- value.Contains("infinity", StringComparison.InvariantCultureIgnoreCase))
- {
- if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var doubleResult))
- return new PrimitiveValue(doubleResult);
- }
-
- // Long.
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longResult))
- {
- return new PrimitiveValue(longResult);
- }
- // Try hex format. For whatever reason, HexNumber does not allow a 0x prefix so we manually
- // get rid of it.
- if (value.IndexOf("0x", StringComparison.InvariantCultureIgnoreCase) != -1)
- {
- var hexDigits = value.TrimStart();
- if (hexDigits.StartsWith("0x"))
- hexDigits = hexDigits.Substring(2);
-
- if (long.TryParse(hexDigits, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var hexResult))
- return new PrimitiveValue(hexResult);
- }
-
- ////TODO: allow trailing width specifier
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Equivalent to <see cref="type"/>.
- /// </summary>
- /// <returns>Type code for value stored in struct.</returns>
- public TypeCode GetTypeCode()
- {
- return type;
- }
-
- /// <summary>
- /// Convert the value to a boolean.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted boolean value.</returns>
- public bool ToBoolean(IFormatProvider provider = null)
- {
- switch (type)
- {
- case TypeCode.Boolean:
- return m_BoolValue;
- case TypeCode.Char:
- return m_CharValue != default;
- case TypeCode.Byte:
- return m_ByteValue != default;
- case TypeCode.SByte:
- return m_SByteValue != default;
- case TypeCode.Int16:
- return m_ShortValue != default;
- case TypeCode.UInt16:
- return m_UShortValue != default;
- case TypeCode.Int32:
- return m_IntValue != default;
- case TypeCode.UInt32:
- return m_UIntValue != default;
- case TypeCode.Int64:
- return m_LongValue != default;
- case TypeCode.UInt64:
- return m_ULongValue != default;
- case TypeCode.Single:
- return !Mathf.Approximately(m_FloatValue, default);
- case TypeCode.Double:
- return NumberHelpers.Approximately(m_DoubleValue, default);
- default:
- return default;
- }
- }
-
- /// <summary>
- /// Convert the value to a byte.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted byte value.</returns>
- public byte ToByte(IFormatProvider provider = null)
- {
- return (byte)ToInt64(provider);
- }
-
- /// <summary>
- /// Convert the value to a char.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted char value.</returns>
- public char ToChar(IFormatProvider provider = null)
- {
- switch (type)
- {
- case TypeCode.Char:
- return m_CharValue;
- case TypeCode.Int16:
- case TypeCode.Int32:
- case TypeCode.Int64:
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- case TypeCode.UInt64:
- return (char)ToInt64(provider);
- default:
- return default;
- }
- }
-
- /// <summary>
- /// Not supported. Throws <c>NotSupportedException</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Does not return.</returns>
- /// <exception cref="NotSupportedException">Always thrown.</exception>
- public DateTime ToDateTime(IFormatProvider provider = null)
- {
- throw new NotSupportedException("Converting PrimitiveValue to DateTime");
- }
-
- /// <summary>
- /// Convert the value to a decimal.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Value converted to decimal format.</returns>
- public decimal ToDecimal(IFormatProvider provider = null)
- {
- return new decimal(ToDouble(provider));
- }
-
- /// <summary>
- /// Convert the value to a double.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted double value.</returns>
- public double ToDouble(IFormatProvider provider = null)
- {
- switch (type)
- {
- case TypeCode.Boolean:
- if (m_BoolValue)
- return 1;
- return 0;
- case TypeCode.Char:
- return m_CharValue;
- case TypeCode.Byte:
- return m_ByteValue;
- case TypeCode.SByte:
- return m_SByteValue;
- case TypeCode.Int16:
- return m_ShortValue;
- case TypeCode.UInt16:
- return m_UShortValue;
- case TypeCode.Int32:
- return m_IntValue;
- case TypeCode.UInt32:
- return m_UIntValue;
- case TypeCode.Int64:
- return m_LongValue;
- case TypeCode.UInt64:
- return m_ULongValue;
- case TypeCode.Single:
- return m_FloatValue;
- case TypeCode.Double:
- return m_DoubleValue;
- default:
- return default;
- }
- }
-
- /// <summary>
- /// Convert the value to a <c>short</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>short</c> value.</returns>
- public short ToInt16(IFormatProvider provider = null)
- {
- return (short)ToInt64(provider);
- }
-
- /// <summary>
- /// Convert the value to an <c>int</c>
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>int</c> value.</returns>
- public int ToInt32(IFormatProvider provider = null)
- {
- return (int)ToInt64(provider);
- }
-
- /// <summary>
- /// Convert the value to a <c>long</c>
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>long</c> value.</returns>
- public long ToInt64(IFormatProvider provider = null)
- {
- switch (type)
- {
- case TypeCode.Boolean:
- if (m_BoolValue)
- return 1;
- return 0;
- case TypeCode.Char:
- return m_CharValue;
- case TypeCode.Byte:
- return m_ByteValue;
- case TypeCode.SByte:
- return m_SByteValue;
- case TypeCode.Int16:
- return m_ShortValue;
- case TypeCode.UInt16:
- return m_UShortValue;
- case TypeCode.Int32:
- return m_IntValue;
- case TypeCode.UInt32:
- return m_UIntValue;
- case TypeCode.Int64:
- return m_LongValue;
- case TypeCode.UInt64:
- return (long)m_ULongValue;
- case TypeCode.Single:
- return (long)m_FloatValue;
- case TypeCode.Double:
- return (long)m_DoubleValue;
- default:
- return default;
- }
- }
-
- /// <summary>
- /// Convert the value to a <c>sbyte</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>sbyte</c> value.</returns>
- public sbyte ToSByte(IFormatProvider provider = null)
- {
- return (sbyte)ToInt64(provider);
- }
-
- /// <summary>
- /// Convert the value to a <c>float</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>float</c> value.</returns>
- public float ToSingle(IFormatProvider provider = null)
- {
- return (float)ToDouble(provider);
- }
-
- /// <summary>
- /// Convert the value to a <c>string</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>string</c> value.</returns>
- /// <remarks>
- /// Same as calling <see cref="ToString()"/>.
- /// </remarks>
- public string ToString(IFormatProvider provider)
- {
- return ToString();
- }
-
- /// <summary>
- /// Not supported.
- /// </summary>
- /// <param name="conversionType">Ignored.</param>
- /// <param name="provider">Ignored.</param>
- /// <returns>Does not return.</returns>
- /// <exception cref="NotSupportedException">Always thrown.</exception>
- public object ToType(Type conversionType, IFormatProvider provider)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// Convert the value to a <c>ushort</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>ushort</c> value.</returns>
- public ushort ToUInt16(IFormatProvider provider = null)
- {
- return (ushort)ToUInt64();
- }
-
- /// <summary>
- /// Convert the value to a <c>uint</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>uint</c> value.</returns>
- public uint ToUInt32(IFormatProvider provider = null)
- {
- return (uint)ToUInt64();
- }
-
- /// <summary>
- /// Convert the value to a <c>ulong</c>.
- /// </summary>
- /// <param name="provider">Ignored.</param>
- /// <returns>Converted <c>ulong</c> value.</returns>
- public ulong ToUInt64(IFormatProvider provider = null)
- {
- switch (type)
- {
- case TypeCode.Boolean:
- if (m_BoolValue)
- return 1;
- return 0;
- case TypeCode.Char:
- return m_CharValue;
- case TypeCode.Byte:
- return m_ByteValue;
- case TypeCode.SByte:
- return (ulong)m_SByteValue;
- case TypeCode.Int16:
- return (ulong)m_ShortValue;
- case TypeCode.UInt16:
- return m_UShortValue;
- case TypeCode.Int32:
- return (ulong)m_IntValue;
- case TypeCode.UInt32:
- return m_UIntValue;
- case TypeCode.Int64:
- return (ulong)m_LongValue;
- case TypeCode.UInt64:
- return m_ULongValue;
- case TypeCode.Single:
- return (ulong)m_FloatValue;
- case TypeCode.Double:
- return (ulong)m_DoubleValue;
- default:
- return default;
- }
- }
-
- /// <summary>
- /// Return a boxed version of the value.
- /// </summary>
- /// <returns>A boxed GC heap object.</returns>
- /// <remarks>
- /// This method always allocates GC heap memory.
- /// </remarks>
- public object ToObject()
- {
- switch (m_Type)
- {
- case TypeCode.Boolean: return m_BoolValue;
- case TypeCode.Char: return m_CharValue;
- case TypeCode.Byte: return m_ByteValue;
- case TypeCode.SByte: return m_SByteValue;
- case TypeCode.Int16: return m_ShortValue;
- case TypeCode.UInt16: return m_UShortValue;
- case TypeCode.Int32: return m_IntValue;
- case TypeCode.UInt32: return m_UIntValue;
- case TypeCode.Int64: return m_LongValue;
- case TypeCode.UInt64: return m_ULongValue;
- case TypeCode.Single: return m_FloatValue;
- case TypeCode.Double: return m_DoubleValue;
- default: return null;
- }
- }
-
- /// <summary>
- /// Create a PrimitiveValue from the given "blittable"/struct value.
- /// </summary>
- /// <param name="value">A value.</param>
- /// <typeparam name="TValue">Type of value to convert. Must be either an <c>enum</c>
- /// or one of the C# primitive value types (<c>bool</c>, <c>int</c>, <c>float</c>, etc.).</typeparam>
- /// <returns>The PrimitiveValue converted from <paramref name="value"/>. If it is an
- /// <c>enum</c> type, the PrimitiveValue will hold a value of the enum's underlying
- /// type (i.e. <c>Type.GetEnumUnderlyingType</c>).</returns>
- /// <exception cref="ArgumentException">No conversion exists from the given <typeparamref name="TValue"/>
- /// type.</exception>
- public static PrimitiveValue From<TValue>(TValue value)
- where TValue : struct
- {
- var type = typeof(TValue);
- if (type.IsEnum)
- type = type.GetEnumUnderlyingType();
-
- var typeCode = Type.GetTypeCode(type);
- switch (typeCode)
- {
- case TypeCode.Boolean: return new PrimitiveValue(Convert.ToBoolean(value));
- case TypeCode.Char: return new PrimitiveValue(Convert.ToChar(value));
- case TypeCode.Byte: return new PrimitiveValue(Convert.ToByte(value));
- case TypeCode.SByte: return new PrimitiveValue(Convert.ToSByte(value));
- case TypeCode.Int16: return new PrimitiveValue(Convert.ToInt16(value));
- case TypeCode.Int32: return new PrimitiveValue(Convert.ToInt32(value));
- case TypeCode.Int64: return new PrimitiveValue(Convert.ToInt64(value));
- case TypeCode.UInt16: return new PrimitiveValue(Convert.ToUInt16(value));
- case TypeCode.UInt32: return new PrimitiveValue(Convert.ToUInt32(value));
- case TypeCode.UInt64: return new PrimitiveValue(Convert.ToUInt64(value));
- case TypeCode.Single: return new PrimitiveValue(Convert.ToSingle(value));
- case TypeCode.Double: return new PrimitiveValue(Convert.ToDouble(value));
- }
-
- throw new ArgumentException(
- $"Cannot convert value '{value}' of type '{typeof(TValue).Name}' to PrimitiveValue", nameof(value));
- }
-
- /// <summary>
- /// Create a PrimitiveValue from a boxed value.
- /// </summary>
- /// <param name="value">A value. If <c>null</c>, the result will be <c>default(PrimitiveValue)</c>.
- /// If it is a <c>string</c>, <see cref="FromString"/> is used. Otherwise must be either an <c>enum</c>
- /// or one of the C# primitive value types (<c>bool</c>, <c>int</c>, <c>float</c>, etc.). If it is an
- /// <c>enum</c> type, the PrimitiveValue will hold a value of the enum's underlying
- /// type (i.e. <c>Type.GetEnumUnderlyingType</c>).</param>
- /// <exception cref="ArgumentException">No conversion exists from the type of <paramref name="value"/>.</exception>
- public static PrimitiveValue FromObject(object value)
- {
- if (value == null)
- return new PrimitiveValue();
-
- if (value is string stringValue)
- return FromString(stringValue);
-
- if (value is bool b)
- return new PrimitiveValue(b);
- if (value is char ch)
- return new PrimitiveValue(ch);
- if (value is byte bt)
- return new PrimitiveValue(bt);
- if (value is sbyte sbt)
- return new PrimitiveValue(sbt);
- if (value is short s)
- return new PrimitiveValue(s);
- if (value is ushort us)
- return new PrimitiveValue(us);
- if (value is int i)
- return new PrimitiveValue(i);
- if (value is uint ui)
- return new PrimitiveValue(ui);
- if (value is long l)
- return new PrimitiveValue(l);
- if (value is ulong ul)
- return new PrimitiveValue(ul);
- if (value is float f)
- return new PrimitiveValue(f);
- if (value is double d)
- return new PrimitiveValue(d);
-
- // Enum.
- if (value is Enum)
- {
- var underlyingType = value.GetType().GetEnumUnderlyingType();
- var underlyingTypeCode = Type.GetTypeCode(underlyingType);
- switch (underlyingTypeCode)
- {
- case TypeCode.Byte: return new PrimitiveValue((byte)value);
- case TypeCode.SByte: return new PrimitiveValue((sbyte)value);
- case TypeCode.Int16: return new PrimitiveValue((short)value);
- case TypeCode.Int32: return new PrimitiveValue((int)value);
- case TypeCode.Int64: return new PrimitiveValue((long)value);
- case TypeCode.UInt16: return new PrimitiveValue((ushort)value);
- case TypeCode.UInt32: return new PrimitiveValue((uint)value);
- case TypeCode.UInt64: return new PrimitiveValue((ulong)value);
- }
- }
-
- throw new ArgumentException($"Cannot convert '{value}' to primitive value", nameof(value));
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a bool.
- /// </summary>
- /// <param name="value">A boolean value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(bool value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a character.
- /// </summary>
- /// <param name="value">A character.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(char value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a byte.
- /// </summary>
- /// <param name="value">A byte value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(byte value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a signed byte.
- /// </summary>
- /// <param name="value">A signed byte value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(sbyte value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a short.
- /// </summary>
- /// <param name="value">A short value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(short value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding an unsigned short.
- /// </summary>
- /// <param name="value">An unsigned short value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(ushort value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding an int.
- /// </summary>
- /// <param name="value">An int value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(int value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding an unsigned int.
- /// </summary>
- /// <param name="value">An unsigned int value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(uint value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a long.
- /// </summary>
- /// <param name="value">A long value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(long value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a ulong.
- /// </summary>
- /// <param name="value">An unsigned long value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(ulong value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a float.
- /// </summary>
- /// <param name="value">A float value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(float value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Create a PrimitiveValue holding a double.
- /// </summary>
- /// <param name="value">A double value.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static implicit operator PrimitiveValue(double value)
- {
- return new PrimitiveValue(value);
- }
-
- // The following methods exist only to make the annoying Microsoft code analyzer happy.
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromBoolean(bool value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromChar(char value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromByte(byte value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromSByte(sbyte value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromInt16(short value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromUInt16(ushort value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromInt32(int value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromUInt32(uint value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromInt64(long value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromUInt64(ulong value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromSingle(float value)
- {
- return new PrimitiveValue(value);
- }
-
- /// <summary>
- /// Constructs a <c>PrimitiveValue</c> from <paramref name="value"/>.
- /// </summary>
- /// <param name="value">The value to be stored in the returned <c>PrimitiveValue</c>.</param>
- /// <returns>A <c>PrimitiveValue</c> set to <paramref name="value"/></returns>
- public static PrimitiveValue FromDouble(double value)
- {
- return new PrimitiveValue(value);
- }
- }
- }
|