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

Last change on this file since 1314 was 1314, checked in by epitzer, 11 years ago

rename ICustomSerializer to ICompoundSerializer. (#506)

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