From 0bd6b086f65835e3a978c1d5d12c434832241bd4 Mon Sep 17 00:00:00 2001 From: Marc Hernandez Date: Sun, 28 Apr 2024 15:00:48 -0700 Subject: [PATCH] x) Remove some Meta things from the debug view x) Better resource handling. Resources can be subclasses of interfaces now x) Add a bit of logging x) Add ser/deser to and from Attributes x) If saving backing fields, use short names (ie the prop name) x) Default to attributes and shortnames --- imm/Imm.cs | 5 +++ res/Resource.cs | 33 +++++++++------ ser/XmlFormatter2.cs | 96 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 103 insertions(+), 31 deletions(-) diff --git a/imm/Imm.cs b/imm/Imm.cs index 20e86ee..631d9dd 100644 --- a/imm/Imm.cs +++ b/imm/Imm.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; @@ -74,9 +75,11 @@ public record class Versioned protected MetaData MetaStorage = new(); + [DebuggerBrowsable(DebuggerBrowsableState.Never)] public MetaData Meta => MetaStorage; [lib.Dont] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ChangeDelegate OnChange = (x, y) => {}; public T Process( Func fn, string reason = "" ) @@ -120,6 +123,7 @@ public record class Recorded : Versioned { } + [DebuggerBrowsable(DebuggerBrowsableState.Never)] new public MetaData Meta => MetaStorage as MetaData; @@ -197,6 +201,7 @@ public record class Timed : Recorded { } + [DebuggerBrowsable(DebuggerBrowsableState.Never)] new public MetaData Meta => MetaStorage as MetaData; public TimeSpan Since => Meta.TouchedAt - Meta.Old?.Meta.TouchedAt ?? TimeSpan.MaxValue; diff --git a/res/Resource.cs b/res/Resource.cs index 27d4fd4..9f7ce2f 100644 --- a/res/Resource.cs +++ b/res/Resource.cs @@ -12,8 +12,13 @@ using System.Threading; namespace res { + using ImmDefLoad = ImmutableQueue<(string name, Ref)>; + public interface Res_old + { + + } [Serializable] public class Ref : lib.I_Serialize @@ -168,6 +173,7 @@ namespace res //???? Should we just always do this? static public void registerSub( Type baseType ) { + log.info( $"Registering loader for {baseType.Name}" ); Type[] typeParams = new Type[1]; foreach( var mi in baseType.GetMethods() ) @@ -178,25 +184,26 @@ namespace res { foreach( var t in ass.GetTypes() ) { - if( t.IsSubclassOf( baseType ) ) - { - typeParams[0] = t; - var mi_ng = mi.MakeGenericMethod( typeParams ); + if( !baseType.IsAssignableFrom( t ) ) continue; - var loadGenType = typeof(Load<>); + log.debug( $"Making a lodaer for {t.Name}" ); - var loadType = loadGenType.MakeGenericType( t ); + typeParams[0] = t; + var mi_ng = mi.MakeGenericMethod( typeParams ); - var loader = Delegate.CreateDelegate( loadType, mi_ng ); + var loadGenType = typeof(Load<>); - var lhGenType = typeof(LoadHolder<>); + var loadType = loadGenType.MakeGenericType( t ); - var lhType = lhGenType.MakeGenericType( t ); + var loader = Delegate.CreateDelegate( loadType, mi_ng ); - var lh = Activator.CreateInstance( lhType, loader ) as LoadHolder; + var lhGenType = typeof(LoadHolder<>); - ImmutableInterlocked.TryAdd( ref Resource.mgr.m_loaders, t, lh ); - } + var lhType = lhGenType.MakeGenericType( t ); + + var lh = Activator.CreateInstance( lhType, loader ) as LoadHolder; + + ImmutableInterlocked.TryAdd( ref Resource.mgr.m_loaders, t, lh ); } } return; @@ -325,6 +332,8 @@ namespace res Mgr() { + log.info( $"Creating Res.Mgr" ); + var ts = new ThreadStart( deferredLoader ); m_deferredLoader = new Thread( ts ); diff --git a/ser/XmlFormatter2.cs b/ser/XmlFormatter2.cs index 6a26375..3bbea50 100644 --- a/ser/XmlFormatter2.cs +++ b/ser/XmlFormatter2.cs @@ -106,6 +106,21 @@ namespace lib //public record struct CollectionCreator( Func FnCreate ); + //These 2 enums are for serialization + public enum BackingFieldNaming + { + Invalid, + Short, //Use the prop name + Regular, + } + + public enum POD + { + Invalid, + Attributes, + Elements, + } + public class XmlFormatter2Cfg: Config { @@ -119,7 +134,9 @@ namespace lib public Dictionary TypeProxy = new(); //public Dictionary CollectionCreator = new(); - + //For Serialization + public BackingFieldNaming Naming = BackingFieldNaming.Short; + public POD POD = POD.Attributes; public Types TypesDefault = Types.Fields; } @@ -255,6 +272,12 @@ namespace lib } private object Deserialize( XmlElement elem, MemberInfo mi, Type type, object existing /*, object enclosing = null*/ ) + { + string name = mi?.Name ?? "{NOT_FOUND}"; + return Deserialize( elem, mi, type, name, existing ); + } + + private object Deserialize( XmlElement elem, MemberInfo mi, Type type, string name, object existing /*, object enclosing = null*/ ) { try { @@ -262,7 +285,7 @@ namespace lib if( typeCode != TypeCode.Object ) { - return DeserializeConcrete( elem, mi, type ); + return DeserializeConcrete( elem, mi, name, type ); } else { @@ -315,7 +338,7 @@ namespace lib return default( T ); } - private object DeserializeConcrete( XmlElement elem, MemberInfo mi, Type type ) + private object DeserializeConcrete( XmlElement elem, MemberInfo mi, string name, Type type ) { string val = ""; @@ -323,6 +346,10 @@ namespace lib { val = elem.GetAttribute("v"); } + else if( elem.HasAttribute(name) ) + { + val = elem.GetAttribute( name ); + } else { val = elem.InnerText; @@ -523,19 +550,35 @@ namespace lib //This is to convert c# names that would be bad as XML tags name = refl.TypeToIdentifier(name); + // @@@ TODO This doesnt yet handle propNames! if (FilterField(filterFields, doImpls, whitelistFields, childFi as MemberInfo, name)) continue; - XmlElement childElem = getNamedChild(allChildren, name); - if( childElem == null && !string.IsNullOrEmpty( propName ) ) childElem = getNamedChild( allChildren, propName ); + string attValue = elem.GetAttribute( name ); + if( !string.IsNullOrWhiteSpace( propName ) && string.IsNullOrWhiteSpace( attValue ) ) attValue = elem.GetAttribute( propName ); - if (childElem != null) + if( !string.IsNullOrWhiteSpace( attValue ) ) { - object existingObj = childFi.GetValue(obj); + object existingObj = childFi.GetValue(obj); - object childObj = Deserialize(childElem, childFi, childFi.FieldType, existingObj); + object childObj = DeserializeConcrete(elem, childFi, attValue, childFi.FieldType); - childFi.SetValue(obj, childObj); + childFi.SetValue(obj, childObj); } + else + { + XmlElement childElem = getNamedChild(allChildren, name); + if( childElem == null && !string.IsNullOrWhiteSpace( propName ) ) childElem = getNamedChild( allChildren, propName ); + + if (childElem != null) + { + object existingObj = childFi.GetValue(obj); + + object childObj = Deserialize(childElem, childFi, childFi.FieldType, existingObj); + + childFi.SetValue(obj, childObj); + } + } + } } @@ -971,8 +1014,6 @@ namespace lib private void Serialize( XmlWriter writer, MemberInfo mi, object root, string name, int depth, bool forceType ) { - writer.WriteStartElement( name ); - if( root != null ) { Type type = root.GetType(); @@ -981,10 +1022,17 @@ namespace lib if( typeCode != TypeCode.Object ) { - SerializeConcrete( writer, mi, root, forceType ); + if( m_cfg.POD == POD.Elements || forceType ) writer.WriteStartElement( name ); + + SerializeConcrete( writer, mi, root, name, forceType ); + + if( m_cfg.POD == POD.Elements || forceType ) writer.WriteEndElement(); + + return; } else { + writer.WriteStartElement( name ); if( !type.IsArray ) { if( IsEnumerable( type )) @@ -1004,20 +1052,26 @@ namespace lib } else { + writer.WriteStartElement( name ); + writer.WriteAttributeString( "v", "null" ); } writer.WriteEndElement(); } - private void SerializeConcrete( XmlWriter writer, MemberInfo mi, object root, bool forceType ) + private void SerializeConcrete( XmlWriter writer, MemberInfo mi, object root, string name, bool forceType ) { //TODO: Only write this out if debugging. - if( forceType ) + if( forceType || m_cfg.POD == POD.Elements ) { - writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) ); + if( forceType ) writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) ); + writer.WriteAttributeString( "v", root.ToString() ); + } + else + { + writer.WriteAttributeString( name, root.ToString() ); } - writer.WriteAttributeString( "v", root.ToString() ); } private void SerializeCollection( XmlWriter writer, MemberInfo mi, object root, int depth ) @@ -1158,12 +1212,12 @@ namespace lib String name = childFi.Name; var dontAtt = childFi.GetCustomAttributes(); - + string propName = ""; if( name.StartsWith( "<" ) && name.EndsWith( "BackingField" ) ) { var gtIndex = name.IndexOf( '>' ); - var propName = name.Substring( 1, gtIndex - 1 ); + propName = name.Substring( 1, gtIndex - 1 ); var propInfo = narrowType.GetProperty( propName ); @@ -1189,7 +1243,11 @@ namespace lib name = refl.TypeToIdentifier(name); - Serialize(writer, childFi, childFi.GetValue(root), name, depth + 1, false); + var finalName = (m_cfg.Naming == BackingFieldNaming.Short && !string.IsNullOrEmpty( propName )) ? + propName : + name; + + Serialize(writer, childFi, childFi.GetValue(root), finalName, depth + 1, false); } }