2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-06-27 05:23:13 +00:00

ResourceTemplate 2.0

This commit is contained in:
2021-05-25 17:06:19 +03:00
parent c8683e17e9
commit 82cbe3b01c
26 changed files with 1105 additions and 272 deletions

View File

@ -0,0 +1,49 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace Esiur.Resource.Template
{
public class ArgumentTemplate
{
public string Name { get; set; }
public TemplateDataType Type { get; set; }
public ParameterInfo ParameterInfo { get; set; }
public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset)
{
var cs = (uint)data[offset++];
var name = DC.GetString(data, offset, cs);
offset += cs;
var (size, type) = TemplateDataType.Parse(data, offset);
return (cs + 1 + size, new ArgumentTemplate(name, type));
}
public ArgumentTemplate()
{
}
public ArgumentTemplate(string name, TemplateDataType type)
{
Name = name;
Type = type;
}
public byte[] Compose()
{
var name = DC.ToBytes(Name);
return new BinaryList()
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(Type.Compose())
.ToArray();
}
}
}

View File

@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
{
public class AttributeTemplate : MemberTemplate
{
public PropertyInfo Info
public PropertyInfo PropertyInfo
{
get;
set;

View File

@ -18,7 +18,9 @@ namespace Esiur.Resource.Template
public bool Listenable { get; set; }
public EventInfo Info { get; set; }
public EventInfo EventInfo { get; set; }
public TemplateDataType ArgumentType { get; set; }
public override byte[] Compose()
{
@ -26,12 +28,12 @@ namespace Esiur.Resource.Template
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return new BinaryList()
.AddUInt8(Listenable ? (byte) 0x58 : (byte) 0x50)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ArgumentType.Compose())
.AddInt32(exp.Length)
.AddUInt8Array(exp)
.ToArray();
@ -41,15 +43,17 @@ namespace Esiur.Resource.Template
.AddUInt8(Listenable ? (byte) 0x48 : (byte) 0x40)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ArgumentType.Compose())
.ToArray();
}
public EventTemplate(ResourceTemplate template, byte index, string name, string expansion = null, bool listenable=false)
public EventTemplate(ResourceTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false)
:base(template, MemberType.Property, index, name)
{
this.Expansion = expansion;
this.Listenable = listenable;
this.ArgumentType = argumentType;
}
}
}

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@ -16,7 +17,17 @@ namespace Esiur.Resource.Template
set;
}
public bool IsVoid
//public bool IsVoid
//{
// get;
// set;
//}
public TemplateDataType ReturnType { get; set; }
public ArgumentTemplate[] Arguments { get; set; }
public MethodInfo MethodInfo
{
get;
set;
@ -25,30 +36,40 @@ namespace Esiur.Resource.Template
public override byte[] Compose()
{
var name = base.Compose();
var bl = new BinaryList()
//.AddUInt8(Expansion != null ? (byte)0x10 : (byte)0)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ReturnType.Compose())
.AddUInt8((byte)Arguments.Length);
for (var i = 0; i < Arguments.Length; i++)
bl.AddUInt8Array(Arguments[i].Compose());
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return new BinaryList().AddUInt8((byte)(0x10 | (IsVoid ? 0x8 : 0x0)))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddInt32(exp.Length)
.AddUInt8Array(exp)
.ToArray();
bl.AddInt32(exp.Length)
.AddUInt8Array(exp);
bl.InsertUInt8(0, 0x10);
}
else
return new BinaryList().AddUInt8((byte)(IsVoid ? 0x8 : 0x0))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.ToArray();
bl.InsertUInt8(0, 0x0);
return bl.ToArray();
}
public FunctionTemplate(ResourceTemplate template, byte index, string name,bool isVoid, string expansion = null)
:base(template, MemberType.Property, index, name)
public FunctionTemplate(ResourceTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null)
: base(template, MemberType.Property, index, name)
{
this.IsVoid = isVoid;
//this.IsVoid = isVoid;
this.Arguments = arguments;
this.ReturnType = returnType;
this.Expansion = expansion;
}
}

View File

@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
{
public class PropertyTemplate : MemberTemplate
{
public enum PropertyPermission:byte
public enum PropertyPermission : byte
{
Read = 1,
Write,
@ -18,12 +18,15 @@ namespace Esiur.Resource.Template
}
public PropertyInfo Info
public PropertyInfo PropertyInfo
{
get;
set;
}
public TemplateDataType ValueType { get; set; }
/*
public bool Serilize
{
@ -32,12 +35,13 @@ namespace Esiur.Resource.Template
*/
//bool ReadOnly;
//IIPTypes::DataType ReturnType;
public PropertyPermission Permission {
public PropertyPermission Permission
{
get;
set;
}
public bool Recordable
{
get;
@ -84,6 +88,7 @@ namespace Esiur.Resource.Template
.AddUInt8((byte)(0x38 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(wexp.Length)
.AddUInt8Array(wexp)
.AddInt32(rexp.Length)
@ -97,6 +102,7 @@ namespace Esiur.Resource.Template
.AddUInt8((byte)(0x30 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(wexp.Length)
.AddUInt8Array(wexp)
.ToArray();
@ -108,25 +114,30 @@ namespace Esiur.Resource.Template
.AddUInt8((byte)(0x28 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.AddInt32(rexp.Length)
.AddUInt8Array(rexp)
.ToArray();
}
else
{
return new BinaryList()
.AddUInt8((byte)(0x20 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose())
.ToArray();
}
}
public PropertyTemplate(ResourceTemplate template, byte index, string name, string read = null, string write = null, bool recordable = false)
:base(template, MemberType.Property, index, name)
public PropertyTemplate(ResourceTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false)
: base(template, MemberType.Property, index, name)
{
this.Recordable = recordable;
//this.Storage = storage;
this.ReadExpansion = read;
this.WriteExpansion = write;
this.ValueType = valueType;
}
}
}

View File

@ -14,6 +14,7 @@ namespace Esiur.Resource.Template
{
public class ResourceTemplate
{
Guid classId;
string className;
List<MemberTemplate> members = new List<MemberTemplate>();
@ -31,6 +32,8 @@ namespace Esiur.Resource.Template
get { return content; }
}
public Type RuntimeType { get; set; }
public MemberTemplate GetMemberTemplate(MemberInfo member)
{
if (member is MethodInfo)
@ -135,20 +138,137 @@ namespace Esiur.Resource.Template
}
public static Guid GetTypeGuid(Type type) => GetTypeGuid(type.FullName);
public static Guid GetTypeGuid(string typeName)
{
var tn = Encoding.UTF8.GetBytes(typeName);
var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16);
return new Guid(hash);
}
static Type GetElementType(Type type) => type switch
{
{ IsArray: true } => type.GetElementType(),
{ IsEnum: true } => type.GetEnumUnderlyingType(),
(_) => type
};
public static ResourceTemplate[] GetRuntimeTypes(ResourceTemplate template)
{
var list = new List<ResourceTemplate>();
list.Add(template);
Action<ResourceTemplate, List<ResourceTemplate>> getRuntimeTypes = null;
getRuntimeTypes = (ResourceTemplate tmp, List<ResourceTemplate> bag) =>
{
if (template.RuntimeType == null)
return;
// functions
foreach (var f in tmp.functions)
{
var frtt = Warehouse.GetTemplate(GetElementType(f.MethodInfo.ReturnType));
if (frtt != null)
{
if (!bag.Contains(frtt))
{
list.Add(frtt);
getRuntimeTypes(frtt, bag);
}
}
var args = f.MethodInfo.GetParameters();
for(var i = 0; i < args.Length - 1; i++)
{
var fpt = Warehouse.GetTemplate(GetElementType(args[i].ParameterType));
if (fpt != null)
{
if (!bag.Contains(fpt))
{
bag.Add(fpt);
getRuntimeTypes(fpt, bag);
}
}
}
// skip DistributedConnection argument
if (args.Length > 0)
{
var last = args.Last();
if (last.ParameterType != typeof(DistributedConnection))
{
var fpt = Warehouse.GetTemplate(GetElementType(last.ParameterType));
if (fpt != null)
{
if (!bag.Contains(fpt))
{
bag.Add(fpt);
getRuntimeTypes(fpt, bag);
}
}
}
}
}
// properties
foreach (var p in tmp.properties)
{
var pt = Warehouse.GetTemplate(GetElementType(p.PropertyInfo.PropertyType));
if (pt != null)
{
if (!bag.Contains(pt))
{
bag.Add(pt);
getRuntimeTypes(pt, bag);
}
}
}
// events
foreach (var e in tmp.events)
{
var et = Warehouse.GetTemplate(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0]));
if (et != null)
{
if (!bag.Contains(et))
{
bag.Add(et);
getRuntimeTypes(et, bag);
}
}
}
};
getRuntimeTypes(template, list);
return list.ToArray();
}
public ResourceTemplate(Type type)
{
if (!Codec.ImplementsInterface(type, typeof(IResource)))
throw new Exception("Type is not a resource.");
type = ResourceProxy.GetBaseType(type);
// set guid
RuntimeType = type;
var typeName = Encoding.UTF8.GetBytes(type.FullName);
var hash = SHA256.Create().ComputeHash(typeName).Clip(0, 16);
classId = new Guid(hash);
className = type.FullName;
//Console.WriteLine($"Creating {className}");
// set guid
classId = GetTypeGuid(className);
#if NETSTANDARD
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
@ -175,8 +295,9 @@ namespace Esiur.Resource.Template
{
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType));
var pt = new PropertyTemplate(this, i++, pi.Name);
if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
@ -185,7 +306,7 @@ namespace Esiur.Resource.Template
else
pt.ReadExpansion = pi.PropertyType.Name;
pt.Info = pi;
pt.PropertyInfo = pi;
//pt.Serilize = publicAttr.Serialize;
properties.Add(pt);
}
@ -195,7 +316,7 @@ namespace Esiur.Resource.Template
if (attributeAttr != null)
{
var at = new AttributeTemplate(this, 0, pi.Name);
at.Info = pi;
at.PropertyInfo = pi;
attributes.Add(at);
}
}
@ -211,8 +332,9 @@ namespace Esiur.Resource.Template
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
var et = new EventTemplate(this, i++, ei.Name);
et.Info = ei;
var argType = ei.EventHandlerType.GenericTypeArguments[0];
var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType));
et.EventInfo = ei;
if (annotationAttr != null)
et.Expansion = annotationAttr.Annotation;
@ -232,12 +354,32 @@ namespace Esiur.Resource.Template
{
var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true);
var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void));
var returnType = TemplateDataType.FromType(mi.ReturnType);
var args = mi.GetParameters();
if (args.Length > 0)
{
if (args.Last().ParameterType == typeof(DistributedConnection))
args = args.Take(args.Count() - 1).ToArray();
}
var arguments = args.Select(x => new ArgumentTemplate()
{
Name = x.Name,
Type = TemplateDataType.FromType(x.ParameterType),
ParameterInfo = x
})
.ToArray();
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
if (annotationAttr != null)
ft.Expansion = annotationAttr.Annotation;
else
ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name;
ft.MethodInfo = mi;
functions.Add(ft);
}
}
@ -253,8 +395,9 @@ namespace Esiur.Resource.Template
{
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var valueType = TemplateDataType.FromType(pi.PropertyType);
var pt = new PropertyTemplate(this, i++, pi.Name);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
var pt = new PropertyTemplate(this, i++, pi.Name, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
@ -263,7 +406,7 @@ namespace Esiur.Resource.Template
else
pt.ReadExpansion = pi.PropertyType.Name;
pt.Info = pi;
pt.PropertyInfo = pi;
//pt.Serilize = publicAttr.Serialize;
properties.Add(pt);
}
@ -273,7 +416,7 @@ namespace Esiur.Resource.Template
if (attributeAttr != null)
{
var at = new AttributeTemplate(this, 0, pi.Name);
at.Info = pi;
at.PropertyInfo = pi;
attributes.Add(at);
}
}
@ -289,8 +432,10 @@ namespace Esiur.Resource.Template
var annotationAttr = ei.GetCustomAttribute<AnnotationAttribute>(true);
var listenableAttr = ei.GetCustomAttribute<ListenableAttribute>(true);
var et = new EventTemplate(this, i++, ei.Name);
et.Info = ei;
var argType = ei.EventHandlerType.GenericTypeArguments[0];
var et = new EventTemplate(this, i++, ei.Name, TemplateDataType.FromType(argType));
et.EventInfo = ei;
if (annotationAttr != null)
et.Expansion = annotationAttr.Annotation;
@ -309,13 +454,32 @@ namespace Esiur.Resource.Template
if (publicAttr != null)
{
var annotationAttr = mi.GetCustomAttribute<AnnotationAttribute>(true);
var returnType = TemplateDataType.FromType(mi.ReturnType);
var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void));
var args = mi.GetParameters();
if (args.Length > 0)
{
if (args.Last().ParameterType == typeof(DistributedConnection))
args = args.Take(args.Count() - 1).ToArray();
}
var arguments = args.Select(x => new ArgumentTemplate()
{
Name = x.Name,
Type = TemplateDataType.FromType(x.ParameterType),
ParameterInfo = x
})
.ToArray();
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
if (annotationAttr != null)
ft.Expansion = annotationAttr.Annotation;
else
ft.Expansion = "(" + String.Join(",", mi.GetParameters().Where(x=>x.ParameterType != typeof(DistributedConnection)).Select(x=> "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name;
ft.MethodInfo = mi;
functions.Add(ft);
}
}
@ -391,11 +555,27 @@ namespace Esiur.Resource.Template
if (type == 0) // function
{
string expansion = null;
var hasExpansion = ((data[offset] & 0x10) == 0x10);
var isVoid = ((data[offset++] & 0x08) == 0x08);
var hasExpansion = ((data[offset++] & 0x10) == 0x10);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
// return type
var (rts, returnType) = TemplateDataType.Parse(data, offset);
offset += rts;
// arguments count
var argsCount = data[offset++];
List<ArgumentTemplate> arguments = new();
for (var a = 0; a < argsCount; a++)
{
var (cs, argType) = ArgumentTemplate.Parse(data, offset);
arguments.Add(argType);
offset += cs;
}
// arguments
if (hasExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
@ -404,7 +584,7 @@ namespace Esiur.Resource.Template
offset += cs;
}
var ft = new FunctionTemplate(od, functionIndex++, name, isVoid, expansion);
var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion);
od.functions.Add(ft);
}
@ -421,6 +601,10 @@ namespace Esiur.Resource.Template
offset += (uint)data[offset] + 1;
var (dts, valueType) = TemplateDataType.Parse(data, offset);
offset += dts;
if (hasReadExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
@ -437,7 +621,7 @@ namespace Esiur.Resource.Template
offset += cs;
}
var pt = new PropertyTemplate(od, propertyIndex++, name, readExpansion, writeExpansion, recordable);
var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable);
od.properties.Add(pt);
}
@ -451,6 +635,10 @@ namespace Esiur.Resource.Template
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
offset += (uint)data[offset] + 1;
var (dts, argType) = TemplateDataType.Parse(data, offset);
offset += dts;
if (hasExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
@ -459,7 +647,7 @@ namespace Esiur.Resource.Template
offset += cs;
}
var et = new EventTemplate(od, eventIndex++, name, expansion, listenable);
var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable);
od.events.Add(et);

View File

@ -0,0 +1,118 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
namespace Esiur.Resource.Template
{
public struct TemplateDataType
{
public DataType Type { get; set; }
//public string TypeName { get; set; }
public ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplate((Guid)TypeGuid);
public Guid? TypeGuid { get; set; }
//public TemplateDataType(DataType type, string typeName)
//{
// Type = type;
// TypeName = typeName;
//}
public static TemplateDataType FromType(Type type)
{
var t = type switch
{
{ IsArray: true } => type.GetElementType(),
{ IsEnum: true } => type.GetEnumUnderlyingType(),
(_) => type
};
DataType dt = t switch
{
_ when t == typeof(bool) => DataType.Bool,
_ when t == typeof(char) => DataType.Char,
_ when t == typeof(byte) => DataType.UInt8,
_ when t == typeof(sbyte) => DataType.Int8,
_ when t == typeof(short) => DataType.Int16,
_ when t == typeof(ushort) => DataType.UInt16,
_ when t == typeof(int) => DataType.Int32,
_ when t == typeof(uint) => DataType.UInt32,
_ when t == typeof(long) => DataType.Int64,
_ when t == typeof(ulong) => DataType.UInt64,
_ when t == typeof(float) => DataType.Float32,
_ when t == typeof(double) => DataType.Float64,
_ when t == typeof(decimal) => DataType.Decimal,
_ when t == typeof(string) => DataType.String,
_ when t == typeof(DateTime) => DataType.DateTime,
_ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type)
_ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure,
_ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource,
_ => DataType.Void
};
//string tn = dt switch
//{
// DataType.Resource => t.FullName,
// DataType.Structure when t != typeof(Structure) => t.FullName,
// _ => null
//};
Guid? typeGuid = null;
if (dt == DataType.Resource)
typeGuid = ResourceTemplate.GetTypeGuid(t);
if (type.IsArray)
dt = (DataType)((byte)dt | 0x80);
return new TemplateDataType()
{
Type = dt,
TypeGuid = typeGuid
};
}
public byte[] Compose()
{
if (Type == DataType.Resource ||
Type == DataType.ResourceArray)//||
//Type == DataType.DistributedResource ||
//Type == DataType.DistributedResourceArray ||
//Type == DataType.Structure ||
//Type == DataType.StructureArray)
{
var guid = DC.ToBytes((Guid)TypeGuid);
return new BinaryList()
.AddUInt8((byte)Type)
.AddUInt8Array(guid).ToArray();
}
else
return new byte[] { (byte)Type };
}
public override string ToString() => Type.ToString() + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : "";
public static (uint, TemplateDataType) Parse(byte[] data, uint offset)
{
var type = (DataType)data[offset++];
if (type == DataType.Resource ||
type == DataType.ResourceArray)//||
// type == DataType.DistributedResource ||
// type == DataType.DistributedResourceArray)// ||
// type == DataType.Structure ||
// type == DataType.StructureArray)
{
var guid = DC.GetGuid(data, offset);
return (17, new TemplateDataType() { Type = type, TypeGuid = guid });
}
else
return (1, new TemplateDataType() { Type = type });
}
}
}