Free cookie consent management tool by TermsFeed Policy Generator

source: branches/New Persistence Exploration/Persistence/Persistence/DeSerializer.cs @ 1348

Last change on this file since 1348 was 1348, checked in by epitzer, 15 years ago

Rename primitive serializers to formatters and compound/composite serializers to decomposers. (#506)

File size: 6.6 KB
Line 
1using System.Collections.Generic;
2using System;
3using System.Reflection;
4using System.Text;
5
6namespace Persistence {
7
8  public class DeSerializer {
9
10    struct ParentReference { }
11
12    delegate void Setter(object value);
13
14    interface IAccessibleObject {
15      object Obj { get; }     
16      Setter GetSetter(string name);
17    }
18
19    class CustomObject : IAccessibleObject {
20      public object Obj { get; private set; }
21      public readonly List<object> customValues;
22      public CustomObject(object obj) {
23        Obj = obj;
24        customValues = new List<object>();
25      }
26      public void AddValue(object value) {
27        customValues.Add(value);
28      }
29      public Setter GetSetter(string name) {
30        int index = customValues.Count-1;
31        return value => customValues[index] = value;
32      }
33    }
34
35    class CompositeObject : IAccessibleObject {
36      public object Obj { get; private set; }
37      public readonly Dictionary<string, DataMemberAccessor> accessorDict;
38      public CompositeObject(object obj, Dictionary<string, DataMemberAccessor> accessorDict) {
39        Obj = obj;
40        this.accessorDict = new Dictionary<string, DataMemberAccessor>();
41        foreach (KeyValuePair<string, DataMemberAccessor> pair in accessorDict) {
42          this.accessorDict.Add(
43            pair.Value.Name,
44            pair.Value);
45        }
46      }
47      public void SetValue(string name, object value) {
48        accessorDict[name].Set(value);
49        accessorDict.Remove(name);
50      }
51      public Setter GetSetter(string name) {
52        return value => accessorDict[name].Set(value);
53      }
54      public void PopulateDefaultValues() {
55        foreach (var pair in accessorDict) {
56          pair.Value.Set(pair.Value.DefaultValue);
57        }       
58      }
59    }
60
61    private delegate void Handler(IParseToken token);
62
63    private readonly Dictionary<int, object> id2obj;
64    private readonly Dictionary<Type, Handler> handlers;
65    private readonly Stack<IAccessibleObject> compositeStack;
66
67    private readonly Dictionary<Type, IFormatter> primitiveSerializers;
68    private readonly List<IDecomposer> customSerializers;
69
70    delegate void Thunk();
71    private List<Thunk> finalFixes;
72
73    public DeSerializer() : this(
74      InterfaceInstantiatior.InstantiateAll<IFormatter>(),
75      InterfaceInstantiatior.InstantiateAll<IDecomposer>()) {}   
76
77    public DeSerializer(
78        IEnumerable<IFormatter> primitiveSerializers,
79        IEnumerable<IDecomposer> customSerializers) {
80      id2obj = new Dictionary<int, object>();
81      compositeStack = new Stack<IAccessibleObject>();
82      handlers = new Dictionary<Type, Handler> {
83                     {typeof (CompositeStart), CompositeStartHandler},
84                     {typeof (CompositeEnd), CompositeEndHandler},
85                     {typeof (Primitive), PrimitiveHandler},
86                     {typeof (Reference), ReferenceHandler},
87                     {typeof (Null), NullHandler}
88                   };
89      this.primitiveSerializers = new Dictionary<Type, IFormatter>();
90      foreach (IFormatter ps in primitiveSerializers) {
91        this.primitiveSerializers.Add(ps.Type, ps);
92      }
93      this.customSerializers = new List<IDecomposer>(customSerializers);
94    }
95
96    public object DeSerialize(IEnumerable<IParseToken> tokens) {
97      finalFixes = new List<Thunk>();
98      foreach (IParseToken token in tokens) {
99        handlers[token.GetType()].Invoke(token);
100      }
101      foreach (Thunk fix in finalFixes) {
102        fix();
103      }
104      return compositeStack.Pop().Obj;
105    }
106
107    private void CompositeStartHandler(IParseToken token) {
108      CompositeStart start = (CompositeStart)token;
109      object instance;
110      if (FindCompoundSerializer(start.Type) != null) {
111        instance = new ParentReference();
112        compositeStack.Push(new CustomObject(instance));       
113      } else {       
114        instance = Activator.CreateInstance(start.Type, true);
115        Dictionary<string, DataMemberAccessor> accessorDict =
116          StorableAttribute.GetAutostorableAccessors(instance);
117        compositeStack.Push(new CompositeObject(instance, accessorDict));       
118      }
119      if ( start.Id != null )
120        id2obj.Add((int)start.Id, instance);
121    }
122    private void CompositeEndHandler(IParseToken token) {
123      CompositeEnd end = (CompositeEnd)token;
124      IDecomposer decomposer = FindCompoundSerializer(end.Type);
125      if (decomposer != null) {
126        CustomObject customObject = (CustomObject)compositeStack.Pop();
127        object deserializedObject =
128          decomposer.DeSerialize(customObject.customValues, end.Type);
129        if ( end.Id != null )
130          id2obj[(int)end.Id] = deserializedObject;       
131        SetValue(end.Name, deserializedObject);         
132      } else {
133        CompositeObject compositeObject = (CompositeObject)compositeStack.Pop();
134        compositeObject.PopulateDefaultValues();
135        SetValue(end.Name, compositeObject.Obj);
136      }
137    }
138    private IDecomposer FindCompoundSerializer(Type type) {
139      foreach (IDecomposer serializer in customSerializers) {
140        if (serializer.CanSerialize(type))
141          return serializer;
142      }
143      return null;
144    }
145    private void PrimitiveHandler(IParseToken token) {
146      Primitive primitive = (Primitive)token;
147      object value = primitiveSerializers[primitive.Type].DeSerialize(primitive.SerializedValue);
148      if ( ! value.GetType().IsValueType )
149        id2obj[(int)primitive.Id] = value;
150      SetValue(primitive.Name, value);
151    }
152    private void ReferenceHandler(IParseToken token) {
153      Reference reference = (Reference)token;
154      object referredObject = id2obj[reference.Id];
155      SetValue(reference.Name, id2obj[reference.Id]);
156      if (referredObject is ParentReference) {
157        Setter set = compositeStack.Peek().GetSetter(reference.Name);       
158        int id = reference.Id;
159        finalFixes.Add(() => set(id2obj[id]));
160      }
161    }
162    private void NullHandler(IParseToken token) {
163      Null nil = (Null)token;
164      SetValue(nil.Name, null);
165    }
166    private void SetValue(string name, object value) {
167      if (compositeStack.Count == 0) {
168        compositeStack.Push(new CompositeObject(value, new Dictionary<string, DataMemberAccessor>()));
169      } else {
170        object accessibleObject = compositeStack.Peek();
171        if (accessibleObject is CompositeObject) {
172          ((CompositeObject)accessibleObject).SetValue(name, value);
173        } else if (accessibleObject is CustomObject) {
174          ((CustomObject)accessibleObject).AddValue(value);
175        }
176      }
177    }
178  }
179}
Note: See TracBrowser for help on using the repository browser.