From 72a28b5f81231f5a173a0fae88613f810a90e4b8 Mon Sep 17 00:00:00 2001 From: Marc Hernandez Date: Sat, 27 Apr 2024 17:51:39 -0700 Subject: [PATCH] Various XML fixes --- imm/Imm.cs | 16 +- ser/XmlFormatter2.cs | 370 +++++++++++++++++++++++++------------------ 2 files changed, 231 insertions(+), 155 deletions(-) diff --git a/imm/Imm.cs b/imm/Imm.cs index 82b2e35..cab2648 100644 --- a/imm/Imm.cs +++ b/imm/Imm.cs @@ -1,15 +1,25 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using lib; namespace imm; +/* +T O D O : +T O D O : +T O D O : +x) Add unit tests for all this. This will definitely benefit from them +*/ + + static public class Util { //This can handle both Timed and Recorded @@ -38,7 +48,7 @@ static public class Util } } - +//[lib.Ser( Types = lib.Types.None )] public record class Versioned where T : Versioned { @@ -61,6 +71,7 @@ public record class Versioned public MetaData Meta => MetaStorage; + [lib.Dont] public ChangeDelegate OnChange = (x, y) => {}; public T Process( Func fn, string reason = "" ) @@ -78,11 +89,14 @@ public record class Versioned } } +//[lib.Ser( Types = lib.Types.None )] public record class Recorded : Versioned where T : Recorded { + new public record class MetaData : Versioned.MetaData { + [lib.Dont] public T? ZZOld { get; internal set; } public T? Old => ZZOld; public string Expression { get; internal set; } = ""; diff --git a/ser/XmlFormatter2.cs b/ser/XmlFormatter2.cs index f57bc61..74ed4a2 100644 --- a/ser/XmlFormatter2.cs +++ b/ser/XmlFormatter2.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using static System.Net.WebRequestMethods; +using System.Linq; /* @@ -44,11 +45,13 @@ namespace lib [Flags] public enum Types { - Fields = 0b_0001, - Props = 0b_0010, - Implied= 0b_0100, + Fields = 0b_0001, + Props = 0b_0010, + Implied = 0b_0100, + Explicit= 0b_1000, + - None = 0b_000, + None = 0b_0000, Default = Fields, All = Fields | Props, } @@ -58,6 +61,14 @@ namespace lib public Types Types { get; set; } = Types.Default; } + public class Do : Attribute + { + } + + public class Dont : Attribute + { + } + public class ChildAttributes : Attribute { public string[] Values { get; private set; } @@ -82,10 +93,10 @@ namespace lib { Invalid, - // + // Breaks on circular datastructures since it will go on forever Tree, - // + // Works for everything. Graph, } @@ -94,7 +105,7 @@ namespace lib public class XmlFormatter2Cfg: Config { - public Datastructure datastructure = Datastructure.Graph; + public Datastructure datastructure = Datastructure.Tree; public int Version = 2; @@ -132,12 +143,12 @@ namespace lib public XmlFormatter2() { - Context = new StreamingContext( StreamingContextStates.All ); + //Context = new StreamingContext( StreamingContextStates.All ); } public XmlFormatter2( XmlFormatter2Cfg cfg ) { - Context = new StreamingContext( StreamingContextStates.All ); + //Context = new StreamingContext( StreamingContextStates.All ); m_cfg = cfg; @@ -406,8 +417,10 @@ namespace lib mm_consType[1] = typeof( StreamingContext ); ConstructorInfo serCons = finalType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, mm_consType, null ); + var context = new StreamingContext( StreamingContextStates.File, obj ); + mm_args[0] = serInfo; - mm_args[1] = Context; + mm_args[1] = context; serCons.Invoke( obj, mm_args ); if( objUnOnDeser != null ) @@ -434,103 +447,117 @@ namespace lib } else { - XmlNodeList allChildren = elem.ChildNodes; - - bool filterFields, filterProps, doImpls, doFields, doProps; - HashSet whitelistFields, whitelistProps; - GetFilters( m_cfg.TypesDefault, mi, finalType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps ); - - /* - List members = new(); - - if( doFields || doImpls ) - { - members.AddRange( refl.GetAllFields( finalType ) ); - } - - if( doProps || doImpls ) - { - members.AddRange( refl.GetAllProperties( finalType ) ); - } - */ - - if( doFields || doImpls ) - { - var fields = refl.GetAllFields( finalType ); - - foreach( FieldInfo childFi in fields ) - { - - String name = childFi.Name; - - //This is to convert c# names that would be bad as XML tags - name = refl.TypeToIdentifier( name ); - - if( FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) ) continue; - - XmlElement childElem = getNamedChild( allChildren, name ); - - if( childElem != null ) - { - object existingObj = childFi.GetValue( obj ); - - object childObj = Deserialize( childElem, childFi, childFi.FieldType, existingObj ); - - childFi.SetValue( obj, childObj ); - } - } - } - - - if( doProps || doImpls ) - { - var props = refl.GetAllProperties( finalType ); - - foreach( var childPi in props ) - { - String name = childPi.Name; - - name = refl.TypeToIdentifier( name ); - - if( FilterField( filterProps, doImpls, whitelistProps, childPi as PropertyInfo, name ) ) continue; - - XmlElement childElem = getNamedChild( allChildren, name ); - - if( childElem != null ) - { - object existingObj = childPi.GetValue( obj ); - - object childObj = Deserialize( childElem, childPi, childPi.PropertyType, existingObj ); - - var setMethod = childPi.GetSetMethod(); - - if( setMethod != null ) - { - //Object o = Activator.CreateInstance( setMethod.ReflectedType ); - setMethod.Invoke( obj, new object[]{ childObj } ); - - //setMethod.CreateDelegate() - } - else - { - childPi.SetValue( obj, childObj ); - } - - } - } - } - - + HydrateObjectOfNarrowType(elem, mi, finalType, obj); } return obj; } + private void HydrateObjectOfNarrowType(XmlElement elem, MemberInfo mi, Type narrowType, object obj) + { + XmlNodeList allChildren = elem.ChildNodes; + + bool filterFields, filterProps, doImpls, doFields, doProps; + HashSet whitelistFields, whitelistProps; + GetFilters(m_cfg.TypesDefault, mi, narrowType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps); + + if (doFields || doImpls) + { + var fields = refl.GetAllFields(narrowType); + + foreach (FieldInfo childFi in fields) + { + + String name = childFi.Name; + + var dontAtt = childFi.GetCustomAttributes(); + + if( name.StartsWith( "<" ) && name.EndsWith( "BackingField" ) ) + { + var gtIndex = name.IndexOf( '>' ); + + var propName = name.Substring( 1, gtIndex - 1 ); + + var propInfo = narrowType.GetProperty( propName ); + + dontAtt = propInfo.GetCustomAttributes(); + } + + if( dontAtt.Any() ) + { + continue; + } + + //if( name.EndsWith( ) ) + + //This is to convert c# names that would be bad as XML tags + name = refl.TypeToIdentifier(name); + + if (FilterField(filterFields, doImpls, whitelistFields, childFi as MemberInfo, name)) continue; + + XmlElement childElem = getNamedChild(allChildren, name); + + if (childElem != null) + { + object existingObj = childFi.GetValue(obj); + + object childObj = Deserialize(childElem, childFi, childFi.FieldType, existingObj); + + childFi.SetValue(obj, childObj); + } + } + } + + + if (doProps || doImpls) + { + var props = refl.GetAllProperties(narrowType); + + foreach (var childPi in props) + { + String name = childPi.Name; + var dontAtt = childPi.GetCustomAttributes(); + if( dontAtt.Any() ) + { + continue; + } + + name = refl.TypeToIdentifier(name); + + if (FilterField(filterProps, doImpls, whitelistProps, childPi as PropertyInfo, name)) continue; + + XmlElement childElem = getNamedChild(allChildren, name); + + if (childElem != null) + { + object existingObj = childPi.GetValue(obj); + + object childObj = Deserialize(childElem, childPi, childPi.PropertyType, existingObj); + + var setMethod = childPi.GetSetMethod(); + + if (setMethod != null) + { + //Object o = Activator.CreateInstance( setMethod.ReflectedType ); + setMethod.Invoke(obj, new object[] { childObj }); + + //setMethod.CreateDelegate() + } + else + { + childPi.SetValue(obj, childObj); + } + + } + } + } + } + private static bool FilterField( bool filterFields, bool doImpls, HashSet whitelistFields, MemberInfo mi, string name ) { if( doImpls ) { - if( mi.GetCustomAttribute() == null ) return true; + if( mi.GetCustomAttribute( true ) == null ) return true; } if( filterFields && !whitelistFields.Contains( name ) ) return true; @@ -868,7 +895,7 @@ namespace lib if( first ) { - if( m_cfg.datastructure == Datastructure.Graph ) + if (m_cfg.datastructure == Datastructure.Graph) { m_alreadySerialized[refInt] = root; } @@ -878,19 +905,26 @@ namespace lib //* Type typeISerializable = typeof(ISerializable); - if( root is ISerializable ser ) + if (root is ISerializable ser) { + if ((root is Delegate)) + { + return; + } + var serInfo = new SerializationInfo(type, new FormatterConverter()); - ser.GetObjectData( serInfo, Context ); + var context = new StreamingContext(StreamingContextStates.File, root); - foreach( var serMember in serInfo ) + ser.GetObjectData(serInfo, context); + + foreach (var serMember in serInfo) { String name = serMember.Name; - name = refl.TypeToIdentifier( name ); + name = refl.TypeToIdentifier(name); - Serialize( writer, mi, serMember.Value, name, depth, true ); + Serialize(writer, mi, serMember.Value, name, depth, true); } return; @@ -900,9 +934,9 @@ namespace lib var tryType = type; TypeProxy? proxy = null; - while( tryType != typeof(object) ) + while (tryType != typeof(object)) { - if( m_cfg.TypeProxy.TryGetValue( tryType, out var newProxy ) ) + if (m_cfg.TypeProxy.TryGetValue(tryType, out var newProxy)) { proxy = newProxy; break; @@ -911,82 +945,110 @@ namespace lib tryType = tryType.BaseType; } - if( proxy.HasValue ) + if (proxy.HasValue) { - var proxyStr = proxy.Value.ser( root ); - writer.WriteAttributeString( "proxy", proxyStr ); + var proxyStr = proxy.Value.ser(root); + writer.WriteAttributeString("proxy", proxyStr); return; } } //*/ + SerializeObjectOfNarrowType(writer, mi, root, depth, type); + } + } + + private void SerializeObjectOfNarrowType(XmlWriter writer, MemberInfo mi, object root, int depth, Type narrowType) + { + bool filterFields, filterProps, doImpls, doFields, doProps; + HashSet whitelistFields, whitelistProps; + GetFilters(m_cfg.TypesDefault, mi, narrowType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps); + + if (doFields || doImpls) + { + var fields = refl.GetAllFields(narrowType); + + foreach (var childFi in fields) { - bool filterFields, filterProps, doImpls, doFields, doProps; - HashSet whitelistFields, whitelistProps; - GetFilters( m_cfg.TypesDefault, mi, type, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps ); + String name = childFi.Name; + var dontAtt = childFi.GetCustomAttributes(); - if( doFields || doImpls ) + + if( name.StartsWith( "<" ) && name.EndsWith( "BackingField" ) ) { - var fields = refl.GetAllFields( type ); + var gtIndex = name.IndexOf( '>' ); - foreach( var childFi in fields ) - { - String name = childFi.Name; + var propName = name.Substring( 1, gtIndex - 1 ); - if( FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) ) continue; + var propInfo = narrowType.GetProperty( propName ); - object[] objs = childFi.GetCustomAttributes( typeof( NonSerializedAttribute ), true ); - - if( objs.Length > 0 ) - { - continue; - } - - //if( childFi.GetCustomAttribute() ) - - name = refl.TypeToIdentifier( name ); - - Serialize( writer, childFi, childFi.GetValue( root ), name, depth + 1, false ); - } + dontAtt = propInfo.GetCustomAttributes(); } - if( doProps || doImpls ) + + if( dontAtt.Any() ) { - var props = refl.GetAllProperties( type ); - - foreach( var childPi in props ) - { - String name = childPi.Name; - - if( FilterField( filterProps, doImpls, whitelistProps, childPi as MemberInfo, name ) ) continue; - - object[] objs = childPi.GetCustomAttributes( typeof( NonSerializedAttribute ), true ); - - if( objs.Length > 0 ) - { - continue; - } - - name = refl.TypeToIdentifier( name ); - - Serialize( writer, childPi, childPi.GetValue( root ), name, depth + 1, false ); - } + continue; } + if (FilterField(filterFields, doImpls, whitelistFields, childFi as MemberInfo, name)) continue; + + object[] objs = childFi.GetCustomAttributes(typeof(NonSerializedAttribute), true); + + if (objs.Length > 0) + { + continue; + } + + //if( childFi.GetCustomAttribute() ) + + name = refl.TypeToIdentifier(name); + + Serialize(writer, childFi, childFi.GetValue(root), name, depth + 1, false); } } + + if (doProps || doImpls) + { + var props = refl.GetAllProperties(narrowType); + + foreach (var childPi in props) + { + String name = childPi.Name; + + var dontAtt = childPi.GetCustomAttributes(); + if( dontAtt.Any() ) + { + continue; + } + + if (FilterField(filterProps, doImpls, whitelistProps, childPi as MemberInfo, name)) continue; + + object[] objs = childPi.GetCustomAttributes(typeof(NonSerializedAttribute), true); + + if (objs.Length > 0) + { + continue; + } + + name = refl.TypeToIdentifier(name); + + Serialize(writer, childPi, childPi.GetValue(root), name, depth + 1, false); + } + } + } private static void GetFilters( Types TypesDefault, MemberInfo mi, Type type, out bool filterFields, out bool filterProps, out bool doImpls, out bool doFields, out bool doProps, out HashSet whitelistFields, out HashSet whitelistProps ) { - var custWLFields = mi?.GetCustomAttribute(); - var custWLProps = mi?.GetCustomAttribute(); + var custWLFields = mi?.GetCustomAttribute( true ); + var custWLProps = mi?.GetCustomAttribute( true ); filterFields = custWLFields != null; filterProps = custWLProps != null; - var typesTodo = type.GetCustomAttribute()?.Types ?? TypesDefault; + var typesTodo = type.GetCustomAttribute( true )?.Types ?? TypesDefault; doImpls = typesTodo.HasFlag( Types.Implied ); doFields = filterFields || typesTodo.HasFlag( Types.Fields );