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

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

Unify token classes for parsing and formatting, make format specification mandatory. (#506)

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