remove json serialization

This commit is contained in:
Mikhail 2024-06-05 20:52:23 +08:00
parent 716328741c
commit 56bc701e01
5 changed files with 48 additions and 718 deletions

View File

@ -1,78 +1,47 @@
using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.PoolsCore;
using DCFApixels.DragonECS.PoolsCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text;
namespace DCFApixels.DragonECS.Docs namespace DCFApixels.DragonECS.Docs
{ {
[Serializable] [Serializable]
[DataContract] [DataContract]
public class DragonDocs : ISerializable public class DragonDocs
{ {
[NonSerialized]
private List<DragonDocsMeta> _metas = new List<DragonDocsMeta>();
[DataMember] [DataMember]
private SortedDictionary<string, List<DragonDocsMeta>> _groups = new SortedDictionary<string, List<DragonDocsMeta>>(); private readonly DragonDocsMeta[] _metas;
public ReadOnlySpan<DragonDocsMeta> Meta
protected DragonDocs(SerializationInfo info, StreamingContext context)
{ {
get { return new ReadOnlySpan<DragonDocsMeta>(_metas); }
} }
public void GetObjectData(SerializationInfo info, StreamingContext context)
private DragonDocs(DragonDocsMeta[] metas)
{ {
throw new NotImplementedException(); _metas = metas;
}
private DragonDocs() { }
private DragonDocs(List<DragonDocsMeta> metaList)
{
_metas = metaList;
foreach (var docsMeta in _metas)
{
string group = docsMeta.Group;
if (_groups.TryGetValue(group, out List<DragonDocsMeta> groupMetas) == false)
{
groupMetas = new List<DragonDocsMeta>();
_groups.Add(group, groupMetas);
}
groupMetas.Add(docsMeta);
}
} }
public static DragonDocs Generate() public static DragonDocs Generate()
{ {
DragonDocs result = new DragonDocs(); List<DragonDocsMeta> metas = new List<DragonDocsMeta>(256);
List<Type> types = GetTypes(); foreach (var type in GetTypes())
foreach (var type in types)
{ {
TypeMeta meta = type.ToMeta(); metas.Add(new DragonDocsMeta(type.ToMeta()));
DragonDocsMeta docsMeta = new DragonDocsMeta(meta);
result._metas.Add(docsMeta);
string group = meta.Group.Name;
if (result._groups.TryGetValue(group, out List<DragonDocsMeta> groupMetas) == false)
{
groupMetas = new List<DragonDocsMeta>();
result._groups.Add(group, groupMetas);
}
groupMetas.Add(docsMeta);
} }
DragonDocsMeta[] array = metas.ToArray();
return result; Array.Sort(array);
return new DragonDocs(array);
} }
private static List<Type> GetTypes() private static List<Type> GetTypes()
{ {
Type ecsMetaAttributeType = typeof(EcsMetaAttribute); Type metaAttributeType = typeof(EcsMetaAttribute);
List<Type> result = new List<Type>();
Type memberType = typeof(IEcsMember); Type memberType = typeof(IEcsMember);
List<Type> result = new List<Type>(512);
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{ {
var types = assembly.GetTypes(); foreach (var type in assembly.GetTypes())
foreach (var type in types)
{ {
if (memberType.IsAssignableFrom(type) || Attribute.GetCustomAttributes(type, ecsMetaAttributeType, false).Length > 1) if (memberType.IsAssignableFrom(type) || Attribute.GetCustomAttributes(type, metaAttributeType, false).Length > 1)
{ {
result.Add(type); result.Add(type);
} }
@ -80,210 +49,5 @@ namespace DCFApixels.DragonECS.Docs
} }
return result; return result;
} }
#region Serialization
public string SerializeToJson()
{
StringBuilder json = new StringBuilder();
json.Append("{ \"data\": [\r");
foreach (var group in _groups)
{
//json.Append($"\"{group.Key}\": ");
json.Append($"{{ \"key\": \"{group.Key}\",\r\"values\": [");
foreach (var meta in group.Value)
{
meta.SerializeToJson(json);
}
json.Append("] }, \r");
}
json.Append(" ] }");
return json.ToString();
}
private static DragonDocs CreateDocs(ref JsonIterator reader)
{
JsonNode node;
List<DragonDocsMeta> metas = new List<DragonDocsMeta>();
while (reader.Next())
{
node = reader.Next();
if (node.IsKey && node.EqualsString("data") && reader.Next().IsEnter)
{
while (reader.Next().IsEnter && (node = reader.Next()).IsKey && node.EqualsString("key"))
{
node = reader.Next();
string group = node.ToString();
node = reader.Next();
if (node.IsKey && node.EqualsString("values") && reader.Next().IsEnter)
{
while (reader.Next().IsEnter)
{
metas.Add(DragonDocsMeta.DeserializeFromJson(ref reader, group));
}
}
if(reader.Next().IsExit == false)
{
throw new Exception();
}
}
return new DragonDocs(metas);
}
else
{
throw new Exception();
}
}
throw new Exception();
}
public unsafe static DragonDocs DeserializeFromJson(string jsonString)
{
CB.Set(jsonString);
fixed (char* ptr = jsonString)
{
JsonIterator reader = new JsonIterator(ptr, jsonString.Length);
return CreateDocs(ref reader);
}
throw new Exception();
//fixed (char* ptr = jsonString)
//{
// //var result = DragonDocsJsonReader.ReadJson(ptr, jsonString.Length);
//
//
//}
//
//throw new NotImplementedException();
//jsonString = jsonString.Replace("{", "").Replace("}", "").Replace("\"", "");
// Разбиваем JSON строку на пары ключ-значение
//string[] parts = jsonString.Split(new string[] { "key:", "values:[" }, StringSplitOptions.RemoveEmptyEntries);
//string[] parts = jsonString.Split("\"key\":", StringSplitOptions.RemoveEmptyEntries);
//List<DragonDocsMeta> metas = new List<DragonDocsMeta>();
//
//
//for (int i = 1; i < parts.Length; i += 2)
//{
// string key = parts[i];
// int indexOf = key.IndexOf('"');
// key = key.Substring(indexOf + 1, key.IndexOf('"', indexOf + 1) - indexOf - 1);
// string values = parts[i + 1];
//
// Match match = Regex.Match(values, @"""values"": \[(.*?)\].*");
// if (match.Success)
// {
// values = match.Groups[1].Value;
// }
//
// CB.Set(values);
//
//
// string[] metaValues = values.Split(new string[] { "},{" }, StringSplitOptions.None);
//
// foreach (string metaValue in metaValues)
// {
// // Десериализация отдельного метаданных (нужно реализовать метод DeserializeFromJson в DragonDocsMeta)
// DragonDocsMeta meta = DragonDocsMeta.DeserializeFromJson("{" + metaValue + "}", key);
// metas.Add(meta);
// }
//}
//return new DragonDocs(metas);
// Удаляем лишние символы из JSON строки
//json = json.Replace("{", "").Replace("}", "").Replace("\"", "");
//
//// Разбиваем JSON строку на пары ключ-значение
//string[] pairs = json.Split(',');
//
//// Создаем переменные для хранения текущих значений
//string currentKey = "";
//List<DragonDocsMeta> currentMetas = new List<DragonDocsMeta>();
//
//foreach (string pair in pairs)
//{
// string[] keyValue = pair.Split(':');
//
// if (keyValue.Length == 2)
// {
// string key = keyValue[0].Trim();
// string value = keyValue[1].Trim();
//
// if (key == "key")
// {
// currentKey = value;
// }
// else if (key == "values")
// {
// // Очищаем список метаданных перед добавлением новых
// currentMetas.Clear();
//
// // Разбиваем значение на отдельные метаданные и десериализуем каждое из них
// string[] metaValues = value.Split(new string[] { "},{" }, StringSplitOptions.None);
// foreach (string metaValue in metaValues)
// {
// // Десериализация отдельного метаданных (нужно реализовать метод DeserializeFromJson в DragonDocsMeta)
// DragonDocsMeta meta = DragonDocsMeta.DeserializeFromJson("{" + metaValue + "}", currentKey);
// currentMetas.Add(meta);
// }
// }
// }
//}
//return new DragonDocs(currentMetas);
}
//public static DragonDocs DeserializeFromJson(string jsonString)
//{
// //jsonString = jsonString.Replace("{", "").Replace("}", "").Replace("\"", "");
//
// // Разбиваем JSON строку на пары ключ-значение
// //string[] parts = jsonString.Split(new string[] { "key:", "values:[" }, StringSplitOptions.RemoveEmptyEntries);
// string[] parts = jsonString.Split("\"key\":", StringSplitOptions.RemoveEmptyEntries);
// List<DragonDocsMeta> metas = new List<DragonDocsMeta>();
//
//
// for (int i = 1; i < parts.Length; i += 2)
// {
// string key = parts[i];
// int indexOf = key.IndexOf('"');
// key = key.Substring(indexOf + 1, key.IndexOf('"', indexOf + 1) - indexOf - 1);
// string values = parts[i + 1];
//
// Match match = Regex.Match(values, @"""values"": \[(.*?)\].*");
// if (match.Success)
// {
// values = match.Groups[1].Value;
// }
//
// CB.Set(values);
//
//
// string[] metaValues = values.Split(new string[] { "},{" }, StringSplitOptions.None);
//
// foreach (string metaValue in metaValues)
// {
// // Десериализация отдельного метаданных (нужно реализовать метод DeserializeFromJson в DragonDocsMeta)
// DragonDocsMeta meta = DragonDocsMeta.DeserializeFromJson("{" + metaValue + "}", key);
// metas.Add(meta);
// }
// }
// return new DragonDocs(metas);
//
//}
#endregion
} }
} }

View File

@ -1,24 +1,26 @@
using DCFApixels.DragonECS.Internal; using System;
using System; using System.Runtime.Serialization;
using System.Text;
namespace DCFApixels.DragonECS.Docs namespace DCFApixels.DragonECS.Docs
{ {
public class DragonDocsMeta [Serializable]
[DataContract]
public class DragonDocsMeta : IComparable<DragonDocsMeta>
{ {
private Type _sourceType; [NonSerialized] private Type _sourceType;
private bool _isInitSourceType = false; [NonSerialized] private bool _isInitSourceType = false;
public readonly string AssemblyQualifiedName = string.Empty;
public readonly string Name = string.Empty; [DataMember] public readonly string AssemblyQualifiedName = string.Empty;
public readonly bool IsCustomName = false;
public readonly MetaColor Color = MetaColor.BlackColor;
public readonly bool IsCustomColor = false;
public readonly string Autor = string.Empty;
public readonly string Description = string.Empty;
public readonly string Group = string.Empty; [DataMember] public readonly string Name = string.Empty;
public readonly string Tags = string.Empty; [DataMember] public readonly bool IsCustomName = false;
[DataMember] public readonly MetaColor Color = MetaColor.BlackColor;
[DataMember] public readonly bool IsCustomColor = false;
[DataMember] public readonly string Autor = string.Empty;
[DataMember] public readonly string Description = string.Empty;
[DataMember] public readonly string Group = string.Empty;
[DataMember] public readonly string Tags = string.Empty;
public DragonDocsMeta(TypeMeta meta) public DragonDocsMeta(TypeMeta meta)
{ {
@ -49,166 +51,10 @@ namespace DCFApixels.DragonECS.Docs
return _sourceType; return _sourceType;
} }
#region Serialization int IComparable<DragonDocsMeta>.CompareTo(DragonDocsMeta other)
public void SerializeToJson(StringBuilder json)
{ {
json.Append("{"); int c = string.Compare(Group, other.Group);
return c == 0 ? c : string.Compare(Name, other.Name);
SerializeFieldToJson(json, nameof(AssemblyQualifiedName), AssemblyQualifiedName, true, true);
SerializeFieldToJson(json, nameof(Name), Name, true, true);
SerializeFieldToJson(json, nameof(IsCustomName), IsCustomName.ToString().ToLower(), false, true);
SerializeFieldToJson(json, nameof(Color), Color.ToString(), true, true);
SerializeFieldToJson(json, nameof(IsCustomColor), IsCustomColor.ToString().ToLower(), false, true);
SerializeFieldToJson(json, nameof(Autor), Autor, true, false);
SerializeFieldToJson(json, nameof(Description), Description, true, false);
//SerializeFieldToJson(json, nameof(Group), Group, false);
SerializeFieldToJson(json, nameof(Tags), Tags, true, false);
json.Remove(json.Length - 1, 1);
json.Append("}");
} }
private void SerializeFieldToJson(StringBuilder json, string fieldName, string value, bool isString, bool alwaysSerialize)
{
if (alwaysSerialize || !string.IsNullOrEmpty(value))
{
json.Append($"\"{fieldName}\":");
if (isString)
{
json.Append($"\"{value}\"");
}
else
{
json.Append($"{value}");
}
json.Append(",");
}
}
internal static DragonDocsMeta DeserializeFromJson(ref JsonIterator reader, string group)
{
return new DragonDocsMeta(ref reader, group);
}
private unsafe DragonDocsMeta(ref JsonIterator reader, string group)
{
Group = group;
JsonNode node;
int depth = reader.Depth;
while ((node = reader.Next()).Depth >= depth)
{
//TODO тут можно сделать систему которая бы учитывала что порядок полей может меняться по мере разработки.
//Есть идея через рефлекшн разбирать состояние типа, после создавать массив индексов,
//а эти индексы потом могли бы применяться в switch-е в котором кейсы на каждый индекс по порядку
if (node.IsKey && node.EqualsString(nameof(AssemblyQualifiedName)))
{
AssemblyQualifiedName = reader.Next().ToString();
if ((node = reader.Next()).Depth < depth) { break; }
}
if (node.IsKey && node.EqualsString(nameof(Name)))
{
Name = reader.Next().ToString();
if ((node = reader.Next()).Depth < depth) { break; }
}
if (node.IsKey && node.EqualsString(nameof(IsCustomName)))
{
IsCustomName = UnsafeBoolParse(reader.Next().Ptr);
if ((node = reader.Next()).Depth < depth) { break; }
}
if (node.IsKey && node.EqualsString(nameof(Color)))
{
node = reader.Next();
Color = MetaColor.Parse(node.Ptr, node.Length);
if ((node = reader.Next()).Depth < depth) { break; }
}
if (node.IsKey && node.EqualsString(nameof(IsCustomColor)))
{
IsCustomColor = UnsafeBoolParse(reader.Next().Ptr);
if ((node = reader.Next()).Depth < depth) { break; }
}
if (node.IsKey && node.EqualsString(nameof(Autor)))
{
Autor = reader.Next().ToString();
if ((node = reader.Next()).Depth < depth) { break; }
}
if (node.IsKey && node.EqualsString(nameof(Description)))
{
Description = reader.Next().ToString();
if ((node = reader.Next()).Depth < depth) { break; }
}
//if (node.IsKey && node.EqualsString(nameof(Group)))
//{
// Group = reader.Next().ToString();
// if ((node = reader.Next()).Depth < depth) { break; }
//}
if (node.IsKey && node.EqualsString(nameof(Tags)))
{
Tags = reader.Next().ToString();
if ((node = reader.Next()).Depth < depth) { break; }
}
}
}
private static unsafe bool UnsafeBoolParse(char* ptr)
{
return char.ToLower(ptr[0]) == 't';
}
public static DragonDocsMeta DeserializeFromJson(string json, string currentGroup)
{
return new DragonDocsMeta(json, currentGroup);
}
/// <summary> DeserializeFromJson constructor. </summary>
private DragonDocsMeta(string json, string currentGroup)
{
// Удаляем лишние символы из JSON строки
json = json.Replace("{", "").Replace("}", "").Replace("\"", "");
// Разбиваем JSON строку на пары ключ-значение
string[] pairs = json.Split(',');
foreach (string pair in pairs)
{
string[] keyValue = pair.Split(':');
if (keyValue.Length == 2)
{
string key = keyValue[0].Trim();
string value = keyValue[1].Trim();
switch (key)
{
case nameof(AssemblyQualifiedName):
AssemblyQualifiedName = value;
break;
case nameof(Name):
Name = value;
break;
case nameof(IsCustomName):
IsCustomName = bool.Parse(value);
break;
case nameof(Color):
Color = MetaColor.Parse(value);
break;
case nameof(IsCustomColor):
IsCustomColor = bool.Parse(value);
break;
case nameof(Autor):
Autor = value;
break;
case nameof(Description):
Description = value;
break;
case nameof(Tags):
Tags = value;
break;
default: break;
}
}
}
Group = currentGroup;
}
#endregion
} }
} }

View File

@ -1,215 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS.Internal
{
internal unsafe ref struct JsonIterator
{
private char* _jsonPtr;
private int _jsonLength;
private int _depth;
private JsonNode _currentNode;
private char _currentChar;
public int Depth
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _depth; }
}
public char Char
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _jsonPtr[0]; }
}
public JsonNode Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _currentNode; }
}
public JsonIterator(char* jsonPtr, int jsonLength)
{
_jsonPtr = jsonPtr - 1;
_jsonLength = jsonLength + 1;
_depth = 0;
_currentChar = '\0';
_currentNode = default;
}
public JsonNode Next()
{
_currentNode = NextInternal();
return _currentNode;
}
public override string ToString() { return new string(_jsonPtr, 0, _jsonLength); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private JsonNode NextInternal()
{
if (NextSymbol() == false)
{
return new JsonNode(JsonNodeType.NA, null, 0, _depth); ;
}
if (IsEnterChar(_currentChar))
{
_depth++;
return new JsonNode(JsonNodeType.Enter, _jsonPtr, 1, _depth);
}
if (IsExitChar(_currentChar))
{
_depth--;
return new JsonNode(JsonNodeType.Exit, _jsonPtr, 1, _depth);
}
if (_currentChar == '"')
{
return ReadString();
}
if (char.IsLetter(_currentChar))
{
return ReadValue();
}
throw new FormatException("JSON format error.");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private JsonNode ReadString()
{
JsonSpan span = new JsonSpan(_jsonPtr);
bool isEscape = false;
while (Increment())
{
if (_currentChar == '"' && isEscape == false)
{
JsonNodeType type = JsonNodeType.Value;
bool x = NextSymbol();
if (x && _currentChar == ':')
{
type = JsonNodeType.Key;
}
else
{
Deincrement();
}
return new JsonNode(type, span.ptr + 1, span.length, _depth);
}
isEscape = isEscape == false && _currentChar == '\\';
span.length++;
}
throw new FormatException("JSON format error.");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private JsonNode ReadValue()
{
JsonSpan span = new JsonSpan(_jsonPtr);
while (Increment() && (char.IsWhiteSpace(_currentChar) || _currentChar == ',' || _currentChar == ':' || _currentChar == '}' || _currentChar == ']') == false)
{
span.length++;
}
JsonNodeType type = JsonNodeType.Value;
Deincrement();
if (NextSymbol() && _currentChar == ':')
{
type = JsonNodeType.Key;
}
else
{
Deincrement();
}
return new JsonNode(type, span.ptr, span.length + 1, _depth);
}
private ref struct JsonSpan
{
public char* ptr;
public int length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public JsonSpan(char* ptr)
{
this.ptr = ptr;
length = 0;
}
public override string ToString() { return new string(ptr, 0, length); }
}
private bool NextSymbol()
{
bool isNotEnd;
while ((isNotEnd = Increment()) && (char.IsWhiteSpace(_currentChar) || _currentChar == ',')) { }
return isNotEnd;
}
private bool Increment()
{
if (_jsonLength > 1)
{
_jsonPtr++;
_jsonLength--;
_currentChar = _jsonPtr[0];
return true;
}
return false;
}
private void Deincrement()
{
_jsonPtr--;
_jsonLength++;
_currentChar = _jsonPtr[0];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool IsEnterChar(char chr) { return chr == '{' || chr == '['; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool IsExitChar(char chr) { return chr == '}' || chr == ']'; }
}
internal readonly unsafe ref struct JsonNode
{
public readonly JsonNodeType Type;
public readonly char* Ptr;
public readonly int Length;
public readonly int Depth;
public bool IsEnter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Type == JsonNodeType.Enter; }
}
public bool IsExit
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Type == JsonNodeType.Exit; }
}
public bool IsKey
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Type == JsonNodeType.Key; }
}
public bool IsValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Type == JsonNodeType.Value; }
}
public bool IsNotBreak
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Type != JsonNodeType.NA; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public JsonNode(JsonNodeType type, char* ptr, int length, int depth)
{
Type = type;
Ptr = ptr;
Length = length;
Depth = depth;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() { return new string(Ptr, 0, Length); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EqualsString(string str)
{
if (str.Length != Length) { return false; }
for (int i = 0; i < str.Length; i++)
{
if (str[i] != Ptr[i]) { return false; }
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator bool(JsonNode node) { return node.IsNotBreak; }
}
internal enum JsonNodeType : byte
{
NA = 0,
Key = 1, Value = 2,
Enter = 3, Exit = 4,
}
}

View File

@ -1,14 +0,0 @@
using System.IO;
namespace DCFApixels.DragonECS.Internal
{
internal struct JsonStreamReader
{
public StreamReader _stream;
private static char[] _chars;
public void Next()
{
_stream.Read(_chars, 0, 100);
}
}
}

View File

@ -1,7 +1,7 @@
using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.Internal;
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -69,7 +69,8 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
} }
[Serializable]
[DataContract]
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)]
public readonly struct MetaColor : IMetaColor, IEquatable<MetaColor> public readonly struct MetaColor : IMetaColor, IEquatable<MetaColor>
{ {
@ -126,11 +127,11 @@ namespace DCFApixels.DragonECS
public const int DragonCyan = (0 << 24) | (255 << 16) | (156 << 8) | 255; public const int DragonCyan = (0 << 24) | (255 << 16) | (156 << 8) | 255;
#endregion #endregion
[FieldOffset(0)] public readonly int colorCode; [FieldOffset(0), NonSerialized] public readonly int colorCode;
[FieldOffset(3)] public readonly byte r; [FieldOffset(3), DataMember] public readonly byte r;
[FieldOffset(2)] public readonly byte g; [FieldOffset(2), DataMember] public readonly byte g;
[FieldOffset(1)] public readonly byte b; [FieldOffset(1), DataMember] public readonly byte b;
[FieldOffset(0)] public readonly byte a; [FieldOffset(0), DataMember] public readonly byte a;
#region Properties #region Properties
byte IMetaColor.R byte IMetaColor.R
@ -340,63 +341,11 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Other
public override string ToString() { return $"({r}, {g}, {b}, {a})"; } public override string ToString() { return $"({r}, {g}, {b}, {a})"; }
public unsafe static MetaColor Parse(string input)
{
if (input == null) { throw new ArgumentNullException(nameof(input)); }
int length = input.Length;
fixed (char* f = input)
{
return Parse(f, length);
}
}
public unsafe static MetaColor Parse(char* ptr, int length)
{
if (ptr == null) { throw new ArgumentNullException(nameof(ptr)); }
byte r, g, b, a;
Trim(ref ptr, ref length);
r = ParseByte(ref ptr, ref length);
g = ParseByte(ref ptr, ref length);
b = ParseByte(ref ptr, ref length);
a = ParseByte(ref ptr, ref length, true);
return new MetaColor(r, g, b, a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void Trim(ref char* span, ref int length)
{
if (!char.IsWhiteSpace(span[0]) && !char.IsWhiteSpace(span[length - 1])) { return; }
while (char.IsWhiteSpace(span[0])) { span++; length--; }
while (char.IsWhiteSpace(span[--length])) { }
length++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static byte ParseByte(ref char* ptr, ref int length, bool isAplha = false)
{
if (length <= 0) { return isAplha ? byte.MaxValue : byte.MinValue; }
while (char.IsDigit(*ptr) == false)
{
ptr++; length--;
if (length <= 0) { return isAplha ? byte.MaxValue : byte.MinValue; }
}
int value = 0;
while (char.IsDigit(*ptr))
{
value = value * 10 + (*ptr - '0');
ptr++; length--;
if (length <= 0) { break; }
}
if (value < 0 || value > 255)
{
throw new FormatException("Color component value should be between 0 and 255.");
}
return (byte)value;
}
public bool Equals(MetaColor other) { return colorCode == other.colorCode; } public bool Equals(MetaColor other) { return colorCode == other.colorCode; }
public override bool Equals(object obj) { return obj is MetaColor other && Equals(other); } public override bool Equals(object obj) { return obj is MetaColor other && Equals(other); }
public override int GetHashCode() { return colorCode; } public override int GetHashCode() { return colorCode; }
#endregion
} }
} }