DtsodV23
This commit is contained in:
parent
8f4fa3de6e
commit
be5dbfc938
@ -310,7 +310,7 @@ public class DtsodV21 : Dictionary<string, dynamic>, IDtsod
|
|||||||
value = stringValue.Remove(stringValue.Length - 1).ToLong();
|
value = stringValue.Remove(stringValue.Length - 1).ToLong();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
value = stringValue.ToShort();
|
value = stringValue.ToInt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -345,7 +345,7 @@ public class DtsodV22 : Dictionary<string, DtsodV22.ValueStruct>, IDtsod
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type = ValueTypes.Int;
|
type = ValueTypes.Int;
|
||||||
value = stringValue.ToShort();
|
value = stringValue.ToInt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
308
Dtsod/DtsodV23.cs
Normal file
308
Dtsod/DtsodV23.cs
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
// v23
|
||||||
|
// в процессе создания v30 появились идеи по улучшению 20-ой серии
|
||||||
|
// новый парсер (опять)
|
||||||
|
// улучшена сериализация и десериализация листов
|
||||||
|
|
||||||
|
public class DtsodV23 : DtsodDict<string, dynamic>, IDtsod
|
||||||
|
{
|
||||||
|
|
||||||
|
public DtsodVersion Version { get; } = DtsodVersion.V30;
|
||||||
|
public IDictionary<string, dynamic> ToDictionary() => this;
|
||||||
|
|
||||||
|
public DtsodV23() : base() => UpdateLazy();
|
||||||
|
public DtsodV23(IDictionary<string, dynamic> dict) : base(dict) => UpdateLazy();
|
||||||
|
public DtsodV23(string serialized) : this() => Append(Deserialize(serialized));
|
||||||
|
|
||||||
|
static DtsodV23 Deserialize(string text)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
int i = -1; // ++i в ReadName
|
||||||
|
StringBuilder b = new();
|
||||||
|
Dictionary<string, dynamic> output = new();
|
||||||
|
bool partOfDollarList = false;
|
||||||
|
for (; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
string name = ReadName();
|
||||||
|
dynamic value = ReadValue(out bool _);
|
||||||
|
if (partOfDollarList)
|
||||||
|
{
|
||||||
|
if (!output.TryGetValue(name, out var dollarList))
|
||||||
|
{
|
||||||
|
dollarList = new List<dynamic>();
|
||||||
|
output.Add(name, dollarList);
|
||||||
|
}
|
||||||
|
dollarList.Add(value);
|
||||||
|
}
|
||||||
|
else output.Add(name, value);
|
||||||
|
}
|
||||||
|
return new DtsodV23(output);
|
||||||
|
|
||||||
|
string ReadName()
|
||||||
|
{
|
||||||
|
while (i < text.Length - 1)
|
||||||
|
{
|
||||||
|
c = text[++i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
string _name = b.ToString();
|
||||||
|
b.Clear();
|
||||||
|
return _name;
|
||||||
|
case '$':
|
||||||
|
partOfDollarList = true;
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case ';':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
throw new Exception($"DtsodV23.Deserialize() error: unexpected {c}");
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("DtsodV23.Deserialize.ReadName() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic ReadValue(out bool endOfList)
|
||||||
|
{
|
||||||
|
endOfList = false;
|
||||||
|
|
||||||
|
void ReadString()
|
||||||
|
{
|
||||||
|
while ((c != '"' && c != '\'') || (text[i - 1] == '\\' && text[i - 2] != '\\'))
|
||||||
|
{
|
||||||
|
b.Append(c);
|
||||||
|
if (++i >= text.Length) throw new Exception("DtsodV23.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
|
c = text[i];
|
||||||
|
}
|
||||||
|
b.Append('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
DtsodV23 ReadDtsod()
|
||||||
|
{
|
||||||
|
short bracketBalance = 1;
|
||||||
|
c = text[++i]; //пропускает начальный символ '{'
|
||||||
|
while (bracketBalance != 0)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
bracketBalance++;
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
bracketBalance--;
|
||||||
|
if (bracketBalance != 0)
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
ReadString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++i >= text.Length) throw new Exception("DtsodV23.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
|
c = text[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Clear();
|
||||||
|
return Deserialize(b.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<dynamic> ReadList()
|
||||||
|
{
|
||||||
|
List<dynamic> list = new();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
list.Add(ReadValue(out bool _eol));
|
||||||
|
if (_eol) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Clear();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic ParseValue(string value_str)
|
||||||
|
{
|
||||||
|
switch (value_str)
|
||||||
|
{
|
||||||
|
case "true":
|
||||||
|
case "false":
|
||||||
|
return value_str.ToBool();
|
||||||
|
case "null":
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
if (value_str.Contains('"'))
|
||||||
|
return value_str.Substring(1, value_str.Length - 2);
|
||||||
|
else if (value_str.Contains('\''))
|
||||||
|
return value_str[1];
|
||||||
|
else switch (value_str[value_str.Length - 1])
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
return value_str[value_str.Length - 2] == 'u'
|
||||||
|
? value_str.Remove(value_str.Length - 2).ToUShort()
|
||||||
|
: value_str.Remove(value_str.Length - 1).ToShort();
|
||||||
|
case 'u':
|
||||||
|
return value_str.Remove(value_str.Length - 1).ToUInt();
|
||||||
|
case 'i':
|
||||||
|
return value_str[value_str.Length - 2] == 'u'
|
||||||
|
? value_str.Remove(value_str.Length - 2).ToUInt()
|
||||||
|
: value_str.Remove(value_str.Length - 1).ToInt();
|
||||||
|
case 'l':
|
||||||
|
return value_str[value_str.Length - 2] == 'u'
|
||||||
|
? value_str.Remove(value_str.Length - 2).ToULong()
|
||||||
|
: value_str.Remove(value_str.Length - 1).ToLong();
|
||||||
|
case 'b':
|
||||||
|
return value_str[value_str.Length - 2] == 's'
|
||||||
|
? value_str.Remove(value_str.Length - 2).ToSByte()
|
||||||
|
: value_str.Remove(value_str.Length - 1).ToByte();
|
||||||
|
case 'f':
|
||||||
|
return value_str.Remove(value_str.Length - 1).ToFloat();
|
||||||
|
case 'e':
|
||||||
|
return value_str[value_str.Length - 2] == 'd'
|
||||||
|
? value_str.Remove(value_str.Length - 2).ToDecimal()
|
||||||
|
: throw new Exception("can't parse value:" + value_str);
|
||||||
|
default:
|
||||||
|
return value_str.Contains('.')
|
||||||
|
? value_str.ToDouble()
|
||||||
|
: value_str.ToInt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < text.Length - 1)
|
||||||
|
{
|
||||||
|
c = text[++i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
ReadString();
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
case ',':
|
||||||
|
string str = b.ToString();
|
||||||
|
b.Clear();
|
||||||
|
return ParseValue(str);
|
||||||
|
case '[':
|
||||||
|
return ReadList();
|
||||||
|
case ']':
|
||||||
|
endOfList = true;
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
return ReadDtsod();
|
||||||
|
case '=':
|
||||||
|
case ':':
|
||||||
|
case '}':
|
||||||
|
case '$':
|
||||||
|
throw new Exception($"DtsodV23.Deserialize() error: unexpected {c}");
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("DtsodV23.Deserialize.ReadValue() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkipComment()
|
||||||
|
{
|
||||||
|
while (text[i] != '\n')
|
||||||
|
if (++i >= text.Length) throw new Exception("DtsodV23.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static readonly Dictionary<Type, Action<dynamic, StringBuilder>> TypeSerializeFuncs = new()
|
||||||
|
{
|
||||||
|
{ typeof(bool), (val, b) => b.Append(val.ToString()) },
|
||||||
|
{ typeof(char), (val, b) => b.Append('\'').Append(val).Append('\'') },
|
||||||
|
{ typeof(string), (val, b) => b.Append('"').Append(val).Append('"') },
|
||||||
|
{ typeof(byte), (val, b) => b.Append(val.ToString()).Append('b') },
|
||||||
|
{ typeof(sbyte), (val, b) => b.Append(val.ToString()).Append("sb") },
|
||||||
|
{ typeof(short), (val, b) => b.Append(val.ToString()).Append('s') },
|
||||||
|
{ typeof(ushort), (val, b) => b.Append(val.ToString()).Append("us") },
|
||||||
|
{ typeof(int), (val, b) => b.Append(val.ToString()) },
|
||||||
|
{ typeof(uint), (val, b) => b.Append(val.ToString()).Append("ui") },
|
||||||
|
{ typeof(long), (val, b) => b.Append(val.ToString()).Append('l') },
|
||||||
|
{ typeof(ulong), (val, b) => b.Append(val.ToString()).Append("ul") },
|
||||||
|
{ typeof(float), (val, b) => b.Append(val.ToString(CultureInfo.InvariantCulture)).Append('f') },
|
||||||
|
{ typeof(double), (val, b) => b.Append(val.ToString(CultureInfo.InvariantCulture)) },
|
||||||
|
{ typeof(decimal), (val, b) => b.Append(val.ToString(CultureInfo.InvariantCulture)).Append("de") }
|
||||||
|
};
|
||||||
|
short tabscount = -1;
|
||||||
|
protected StringBuilder Serialize(IDictionary<string, dynamic> dtsod, StringBuilder b = null)
|
||||||
|
{
|
||||||
|
tabscount++;
|
||||||
|
if (b is null) b = new StringBuilder();
|
||||||
|
foreach (var pair in dtsod)
|
||||||
|
{
|
||||||
|
b.Append('\t', tabscount).Append(pair.Key).Append(": ");
|
||||||
|
SerializeType(pair.Value);
|
||||||
|
b.Append(";\n");
|
||||||
|
|
||||||
|
void SerializeType(dynamic value)
|
||||||
|
{
|
||||||
|
if (value is IList _list)
|
||||||
|
{
|
||||||
|
b.Append('[');
|
||||||
|
foreach (object el in _list)
|
||||||
|
{
|
||||||
|
SerializeType(el);
|
||||||
|
b.Append(',');
|
||||||
|
}
|
||||||
|
b.Remove(b.Length - 1, 1).Append(']');
|
||||||
|
}
|
||||||
|
else if (value is IDictionary _dict)
|
||||||
|
{
|
||||||
|
b.Append('{');
|
||||||
|
Serialize(value, b);
|
||||||
|
b.Append('}');
|
||||||
|
}
|
||||||
|
else b.Append(TypeSerializeFuncs[value.GetType()].Invoke(value, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabscount--;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Lazy<string> serialized;
|
||||||
|
protected void UpdateLazy() => serialized = new(() => Serialize(this).ToString());
|
||||||
|
public override string ToString() => serialized.Value;
|
||||||
|
}
|
||||||
@ -4,5 +4,6 @@ public enum DtsodVersion : byte
|
|||||||
{
|
{
|
||||||
V21 = 21,
|
V21 = 21,
|
||||||
V22 = 22,
|
V22 = 22,
|
||||||
|
V23 = 23,
|
||||||
V30 = 30
|
V30 = 30
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ public static class DtsodVersionConverter
|
|||||||
{
|
{
|
||||||
DtsodVersion.V21 => new DtsodV21(src.ToDictionary()),
|
DtsodVersion.V21 => new DtsodV21(src.ToDictionary()),
|
||||||
DtsodVersion.V22 => throw new NotImplementedException("Converting dtsods to V22 isn't implemented"),
|
DtsodVersion.V22 => throw new NotImplementedException("Converting dtsods to V22 isn't implemented"),
|
||||||
|
DtsodVersion.V23 => new DtsodV23(src.ToDictionary()),
|
||||||
DtsodVersion.V30 => new DtsodV30(src.ToDictionary()),
|
DtsodVersion.V30 => new DtsodV30(src.ToDictionary()),
|
||||||
_ => throw new Exception($"DtsodVersionConverter.Convert() error: unknown target version <{targetVersion}>"),
|
_ => throw new Exception($"DtsodVersionConverter.Convert() error: unknown target version <{targetVersion}>"),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace DTLib.Dtsod;
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
@ -13,10 +12,6 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
public DtsodV30(IDictionary<string, dynamic> dict) : base(dict) => UpdateLazy();
|
public DtsodV30(IDictionary<string, dynamic> dict) : base(dict) => UpdateLazy();
|
||||||
public DtsodV30(string serialized) : this() => Append(Deserialize(serialized));
|
public DtsodV30(string serialized) : this() => Append(Deserialize(serialized));
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
static void DebugLog(params string[] msg) => PublicLog.Log(msg);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static IDictionary<string, dynamic> Deserialize(string text)
|
static IDictionary<string, dynamic> Deserialize(string text)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
@ -27,7 +22,7 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
Type ReadType()
|
Type ReadType()
|
||||||
{
|
{
|
||||||
|
|
||||||
while (i < text.Length)
|
while (i < text.Length - 1)
|
||||||
{
|
{
|
||||||
c = text[++i];
|
c = text[++i];
|
||||||
switch (c)
|
switch (c)
|
||||||
@ -43,9 +38,10 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
case ':':
|
case ':':
|
||||||
string _type = b.ToString();
|
string _type = b.ToString();
|
||||||
b.Clear();
|
b.Clear();
|
||||||
return TypeHelper.TypeFromString(_type);
|
return TypeHelper.Instance.TypeFromString(_type);
|
||||||
case '=':
|
case '=':
|
||||||
case '"':
|
case '"':
|
||||||
|
case '\'':
|
||||||
case ';':
|
case ';':
|
||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
@ -63,7 +59,7 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
|
|
||||||
string ReadName()
|
string ReadName()
|
||||||
{
|
{
|
||||||
while (i < text.Length)
|
while (i < text.Length - 1)
|
||||||
{
|
{
|
||||||
c = text[++i];
|
c = text[++i];
|
||||||
switch (c)
|
switch (c)
|
||||||
@ -82,6 +78,7 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
return _name;
|
return _name;
|
||||||
case ':':
|
case ':':
|
||||||
case '"':
|
case '"':
|
||||||
|
case '\'':
|
||||||
case ';':
|
case ';':
|
||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
@ -97,12 +94,12 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
throw new Exception("DtsodV30.Deserialize.ReadName() error: end of text\ntext:\n" + text);
|
throw new Exception("DtsodV30.Deserialize.ReadName() error: end of text\ntext:\n" + text);
|
||||||
}
|
}
|
||||||
|
|
||||||
object[] ReadValue()
|
object ReadValue(ref bool endoflist)
|
||||||
{
|
{
|
||||||
void ReadString()
|
void ReadString()
|
||||||
{
|
{
|
||||||
c = text[++i]; //пропускает начальный символ '"'
|
c = text[++i]; //пропускает начальный символ '"'
|
||||||
while (c != '"' || (text[i - 1] == '\\' && text[i - 2] != '\\'))
|
while ((c != '"' && c != '\'') || (text[i - 1] == '\\' && text[i - 2] != '\\'))
|
||||||
{
|
{
|
||||||
b.Append(c);
|
b.Append(c);
|
||||||
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
@ -110,13 +107,13 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool endoflist = false; // выставляется в цикле в ReadValue()
|
|
||||||
List<object> ReadList()
|
List<object> ReadList()
|
||||||
{
|
{
|
||||||
List<dynamic> list = new();
|
List<object> list = new();
|
||||||
while (!endoflist)
|
bool _endoflist = false;
|
||||||
list.Add(CreateInstance(ReadType(), ReadValue()));
|
while (!_endoflist)
|
||||||
endoflist = false;
|
list.Add(CreateInstance(ReadType(), ReadValue(ref _endoflist)));
|
||||||
|
b.Clear();
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +143,7 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
b.Append(c);
|
b.Append(c);
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
|
case '\'':
|
||||||
b.Append('"');
|
b.Append('"');
|
||||||
ReadString();
|
ReadString();
|
||||||
b.Append('"');
|
b.Append('"');
|
||||||
@ -159,10 +157,11 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
c = text[i];
|
c = text[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.Clear();
|
||||||
return Deserialize(b.ToString());
|
return Deserialize(b.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < text.Length)
|
while (i < text.Length-1)
|
||||||
{
|
{
|
||||||
c = text[++i];
|
c = text[++i];
|
||||||
switch (c)
|
switch (c)
|
||||||
@ -176,29 +175,21 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
SkipComment();
|
SkipComment();
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
|
case '\'':
|
||||||
ReadString();
|
ReadString();
|
||||||
break;
|
break;
|
||||||
case ';': // один параметр
|
case ';': // один параметр
|
||||||
case ',': // для листов
|
case ',': // для листов
|
||||||
string str = b.ToString();
|
string str = b.ToString();
|
||||||
b.Clear();
|
b.Clear();
|
||||||
// hardcoded "null" value
|
return str == "null" ? null : str;
|
||||||
return str == "null" ? (new object[] { null }) : (new object[] { str });
|
|
||||||
case '[':
|
case '[':
|
||||||
{
|
return ReadList();
|
||||||
object[] _value = ReadList().ToArray();
|
|
||||||
b.Clear();
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
case ']':
|
case ']':
|
||||||
endoflist = true;
|
endoflist = true;
|
||||||
goto case ',';
|
goto case ',';
|
||||||
case '{':
|
case '{':
|
||||||
{
|
return ReadDictionary();
|
||||||
object[] _value = new object[] { ReadDictionary() };
|
|
||||||
b.Clear();
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
case '=':
|
case '=':
|
||||||
case ':':
|
case ':':
|
||||||
case '}':
|
case '}':
|
||||||
@ -218,25 +209,42 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
}
|
}
|
||||||
|
|
||||||
object CreateInstance(Type type, object[] ctor_args)
|
object CreateInstance(Type type, object ctor_arg)
|
||||||
{
|
{
|
||||||
if (TypeHelper.BaseTypeConstructors.TryGetValue(type, out Func<string, dynamic> ctor))
|
if (TypeHelper.Instance.BaseTypeConstructors.TryGetValue(type, out Func<string, dynamic> ctor))
|
||||||
return (object)ctor.Invoke((string)ctor_args[0]);
|
return (object)ctor.Invoke((string)ctor_arg);
|
||||||
else if (type.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)))
|
else if (type.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)))
|
||||||
return Activator.CreateInstance(type, ctor_args);
|
return Activator.CreateInstance(type, ((IDictionary<string, object>)ctor_arg).Values.ToArray());
|
||||||
else throw new Exception($"type {type.AssemblyQualifiedName} doesn't have DtsodSerializableAttribute");
|
else if (typeof(ICollection).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
var method_As = typeof(TypeHelper).GetMethod("As",
|
||||||
|
System.Reflection.BindingFlags.Static |
|
||||||
|
System.Reflection.BindingFlags.NonPublic)
|
||||||
|
.MakeGenericMethod(type.GetGenericArguments()[0]);
|
||||||
|
object collection = type.GetConstructor(Type.EmptyTypes).Invoke(null);
|
||||||
|
var method_Add = type.GetMethod("Add");
|
||||||
|
Log(method_Add.Name);
|
||||||
|
foreach (object el in (IEnumerable)ctor_arg)
|
||||||
|
{
|
||||||
|
var pel = method_As.Invoke(null, new object[] { el });
|
||||||
|
method_Add.Invoke(collection, new object[] { pel });
|
||||||
|
}
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
else throw new Exception($"can't create instance of {type.FullName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<string, dynamic> output = new();
|
Dictionary<string, dynamic> output = new();
|
||||||
Type type;
|
Type type;
|
||||||
string name;
|
string name;
|
||||||
object[] value;
|
object value;
|
||||||
|
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
type = ReadType();
|
type = ReadType();
|
||||||
name = ReadName();
|
name = ReadName();
|
||||||
value = ReadValue();
|
bool _ = false;
|
||||||
|
value = ReadValue(ref _);
|
||||||
output.Add(name, CreateInstance(type, value));
|
output.Add(name, CreateInstance(type, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,22 +260,32 @@ public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
|||||||
StringBuilder b = new();
|
StringBuilder b = new();
|
||||||
foreach (KeyValuePair<string, dynamic> pair in dtsod)
|
foreach (KeyValuePair<string, dynamic> pair in dtsod)
|
||||||
{
|
{
|
||||||
Type type = pair.Value.GetType();
|
|
||||||
b.Append(TypeHelper.TypeToString(type)).Append(':')
|
}
|
||||||
.Append(pair.Key).Append('=');
|
|
||||||
if (TypeHelper.BaseTypeNames.ContainsKey(type))
|
void SerializeObject(string name, dynamic inst)
|
||||||
|
{
|
||||||
|
Type type = inst.GetType();
|
||||||
|
b.Append(TypeHelper.Instance.TypeToString(type)).Append(':')
|
||||||
|
.Append(name).Append('=');
|
||||||
|
if (TypeHelper.Instance.BaseTypeNames.ContainsKey(type))
|
||||||
{
|
{
|
||||||
if (type == typeof(decimal) || type == typeof(double) || type == typeof(float))
|
if (type == typeof(decimal) || type == typeof(double) || type == typeof(float))
|
||||||
b.Append(pair.Value.ToString(CultureInfo.InvariantCulture));
|
b.Append(inst.ToString(CultureInfo.InvariantCulture));
|
||||||
else b.Append(pair.Value.ToString());
|
else b.Append(inst.ToString());
|
||||||
}
|
}
|
||||||
else if (typeof(IDictionary<string, dynamic>).IsAssignableFrom(type))
|
else if (typeof(IDictionary<string, dynamic>).IsAssignableFrom(type))
|
||||||
b.Append("\n{\n").Append(Serialize(pair.Value, tabsCount++)).Append("};\n");
|
b.Append("\n{\n").Append(Serialize(inst, tabsCount++)).Append("};\n");
|
||||||
else
|
else if (type.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)))
|
||||||
{
|
{
|
||||||
type.GetProperties().Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)));
|
var props = type.GetProperties().Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)));
|
||||||
|
foreach (var prop in props)
|
||||||
|
{
|
||||||
|
var propval = prop.GetValue(inst);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else throw new Exception($"can't serialize type {type.FullName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.ToString();
|
return b.ToString();
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
namespace DTLib.Dtsod;
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
public static class TypeHelper
|
public class TypeHelper
|
||||||
{
|
{
|
||||||
public static readonly Dictionary<Type, Func<string, dynamic>> BaseTypeConstructors = new()
|
static Lazy<TypeHelper> _inst = new();
|
||||||
|
public static TypeHelper Instance => _inst.Value;
|
||||||
|
|
||||||
|
internal readonly Dictionary<Type, Func<string, dynamic>> BaseTypeConstructors = new()
|
||||||
{
|
{
|
||||||
{ typeof(bool), (inp) => inp.ToBool() },
|
{ typeof(bool), (inp) => inp.ToBool() },
|
||||||
{ typeof(char), (inp) => inp.ToChar() },
|
{ typeof(char), (inp) => inp.ToChar() },
|
||||||
@ -20,7 +23,7 @@ public static class TypeHelper
|
|||||||
{ typeof(decimal), (inp) => inp.ToDecimal() }
|
{ typeof(decimal), (inp) => inp.ToDecimal() }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Dictionary<Type, string> BaseTypeNames = new()
|
internal Dictionary<Type, string> BaseTypeNames = new()
|
||||||
{
|
{
|
||||||
{ typeof(bool), "bool" },
|
{ typeof(bool), "bool" },
|
||||||
{ typeof(char), "char" },
|
{ typeof(char), "char" },
|
||||||
@ -38,12 +41,55 @@ public static class TypeHelper
|
|||||||
{ typeof(decimal), "decimal" }
|
{ typeof(decimal), "decimal" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string TypeToString(Type t) =>
|
private DtsodDict<string, Type> ST_extensions = new()
|
||||||
|
{
|
||||||
|
{ "List<bool>", typeof(List<bool>) },
|
||||||
|
{ "List<char>", typeof(List<char>) },
|
||||||
|
{ "List<string>", typeof(List<string>) },
|
||||||
|
{ "List<byte>", typeof(List<byte>) },
|
||||||
|
{ "List<sbyte>", typeof(List<sbyte>) },
|
||||||
|
{ "List<short>", typeof(List<short>) },
|
||||||
|
{ "List<ushort>", typeof(List<ushort>) },
|
||||||
|
{ "List<int>", typeof(List<int>) },
|
||||||
|
{ "List<uint>", typeof(List<uint>) },
|
||||||
|
{ "List<long>", typeof(List<long>) },
|
||||||
|
{ "List<ulong>", typeof(List<ulong>) },
|
||||||
|
{ "List<float>", typeof(List<float>) },
|
||||||
|
{ "List<double>", typeof(List<double>) },
|
||||||
|
{ "List<decimal>", typeof(List<decimal>) },
|
||||||
|
};
|
||||||
|
private DtsodDict<Type, string> TS_extensions = new()
|
||||||
|
{
|
||||||
|
{ typeof(List<bool>), "List<bool>" },
|
||||||
|
{ typeof(List<char>), "List<char>" },
|
||||||
|
{ typeof(List<string>), "List<string>" },
|
||||||
|
{ typeof(List<byte>), "List<byte>" },
|
||||||
|
{ typeof(List<sbyte>), "List<sbyte>" },
|
||||||
|
{ typeof(List<short>), "List<short>" },
|
||||||
|
{ typeof(List<ushort>), "List<ushort>" },
|
||||||
|
{ typeof(List<int>), "List<int>" },
|
||||||
|
{ typeof(List<uint>), "List<uint>" },
|
||||||
|
{ typeof(List<long>), "List<long>" },
|
||||||
|
{ typeof(List<ulong>), "List<ulong>" },
|
||||||
|
{ typeof(List<float>), "List<float>" },
|
||||||
|
{ typeof(List<double>), "List<double>" },
|
||||||
|
{ typeof(List<decimal>), "List<decimal>" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public TypeHelper Extend(string name, Type type)
|
||||||
|
{
|
||||||
|
ST_extensions.Add(name, type);
|
||||||
|
TS_extensions.Add(type, name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TypeToString(Type t) =>
|
||||||
BaseTypeNames.TryGetValue(t, out string name)
|
BaseTypeNames.TryGetValue(t, out string name)
|
||||||
? name
|
? name
|
||||||
: t.AssemblyQualifiedName;
|
: TS_extensions.TryGetValue(t, out name)
|
||||||
|
? name
|
||||||
public static Type TypeFromString(string str) => str switch
|
: t.FullName;
|
||||||
|
public Type TypeFromString(string str) => str switch
|
||||||
{
|
{
|
||||||
"bool" => typeof(bool),
|
"bool" => typeof(bool),
|
||||||
"char" => typeof(char),
|
"char" => typeof(char),
|
||||||
@ -59,8 +105,10 @@ public static class TypeHelper
|
|||||||
"float" => typeof(float),
|
"float" => typeof(float),
|
||||||
"double" => typeof(double),
|
"double" => typeof(double),
|
||||||
"decimal" => typeof(decimal),
|
"decimal" => typeof(decimal),
|
||||||
_ => Type.GetType(str, false) ??
|
_ => ST_extensions.TryGetValue(str, out var t)
|
||||||
throw new Exception($"DtsodV30.Deserialize.ParseType() error: type {str} doesn't exists")
|
? t
|
||||||
|
: Type.GetType(str, false)
|
||||||
|
?? throw new Exception($"DtsodV30.Deserialize.ParseType() error: type {str} doesn't exists")
|
||||||
};
|
};
|
||||||
|
static internal T As<T>(object inst) where T : class => inst as T;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user