source: branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0/Transformers/Transformers.cs @ 14771

Last change on this file since 14771 was 14771, checked in by gkronber, 2 years ago

#2520 added versions to storable types and implemented conversion unit test

File size: 47.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections;
24using System.Collections.Generic;
25using System.ComponentModel;
26using System.Drawing;
27using System.Drawing.Imaging;
28using System.Globalization;
29using System.IO;
30using System.Linq;
31using System.Reflection;
32using Google.ProtocolBuffers;
33using HeuristicLab.Persistence.Core;
34using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
35
36namespace HeuristicLab.Persistence {
37  public abstract class BoxTransformer<T> : Transformer {
38    public override bool CanTransformType(Type type) {
39      return type == typeof(T);
40    }
41
42    public override Box ToBox(object o, Mapper mapper) {
43      var box = Box.CreateBuilder();
44      box.TransformerId = mapper.GetTransformerId(this);
45      box.TypeId = mapper.GetBoxId(o.GetType());
46      Populate(box, (T)o, mapper);
47      return box.Build();
48    }
49    public override object ToObject(Box box, Mapper mapper) {
50      return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper);
51    }
52    protected abstract void Populate(Box.Builder box, T value, Mapper mapper);
53    protected abstract T Extract(Box box, Type type, Mapper mapper);
54  }
55
56  #region Scalar Box Transformers
57  public abstract class BoolBoxTransformer<T> : BoxTransformer<T> {
58    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
59      var b = BoolBox.CreateBuilder();
60      b.Value = ToBoxType(value, mapper);
61      box.SetExtension<BoolBox>(BoolBox.Bool, b.Build());
62    }
63    protected override T Extract(Box box, Type type, Mapper mapper) {
64      return ToValueType(box.GetExtension(BoolBox.Bool).Value, type, mapper);
65    }
66    protected abstract bool ToBoxType(T value, Mapper mapper);
67    protected abstract T ToValueType(bool value, Type type, Mapper mapper);
68  }
69  public abstract class IntBoxTransformer<T> : BoxTransformer<T> {
70    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
71      var b = IntBox.CreateBuilder();
72      b.Value = ToBoxType(value, mapper);
73      box.SetExtension<IntBox>(IntBox.Int, b.Build());
74    }
75    protected override T Extract(Box box, Type type, Mapper mapper) {
76      return ToValueType(box.GetExtension(IntBox.Int).Value, type, mapper);
77    }
78    protected abstract int ToBoxType(T value, Mapper mapper);
79    protected abstract T ToValueType(int value, Type type, Mapper mapper);
80  }
81  public abstract class LongBoxTransformer<T> : BoxTransformer<T> {
82    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
83      var b = LongBox.CreateBuilder();
84      b.Value = ToBoxType(value, mapper);
85      box.SetExtension<LongBox>(LongBox.Long, b.Build());
86    }
87    protected override T Extract(Box box, Type type, Mapper mapper) {
88      return ToValueType(box.GetExtension(LongBox.Long).Value, type, mapper);
89    }
90    protected abstract long ToBoxType(T value, Mapper mapper);
91    protected abstract T ToValueType(long value, Type type, Mapper mapper);
92  }
93  public abstract class UnsignedIntBoxTransformer<T> : BoxTransformer<T> {
94    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
95      var b = UnsignedIntBox.CreateBuilder();
96      b.Value = ToBoxType(value, mapper);
97      box.SetExtension<UnsignedIntBox>(UnsignedIntBox.UnsignedInt, b.Build());
98    }
99    protected override T Extract(Box box, Type type, Mapper mapper) {
100      return ToValueType(box.GetExtension(UnsignedIntBox.UnsignedInt).Value, type, mapper);
101    }
102    protected abstract uint ToBoxType(T value, Mapper mapper);
103    protected abstract T ToValueType(uint value, Type type, Mapper mapper);
104  }
105  public abstract class UnsignedLongBoxTransformer<T> : BoxTransformer<T> {
106    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
107      var b = UnsignedLongBox.CreateBuilder();
108      b.Value = ToBoxType(value, mapper);
109      box.SetExtension<UnsignedLongBox>(UnsignedLongBox.UnsignedLong, b.Build());
110    }
111    protected override T Extract(Box box, Type type, Mapper mapper) {
112      return ToValueType(box.GetExtension(UnsignedLongBox.UnsignedLong).Value, type, mapper);
113    }
114    protected abstract ulong ToBoxType(T value, Mapper mapper);
115    protected abstract T ToValueType(ulong value, Type type, Mapper mapper);
116  }
117  public abstract class FloatBoxTransformer<T> : BoxTransformer<T> {
118    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
119      var b = FloatBox.CreateBuilder();
120      b.Value = ToBoxType(value, mapper);
121      box.SetExtension<FloatBox>(FloatBox.Float, b.Build());
122    }
123    protected override T Extract(Box box, Type type, Mapper mapper) {
124      return ToValueType(box.GetExtension(FloatBox.Float).Value, type, mapper);
125    }
126    protected abstract float ToBoxType(T value, Mapper mapper);
127    protected abstract T ToValueType(float value, Type type, Mapper mapper);
128  }
129  public abstract class DoubleBoxTransformer<T> : BoxTransformer<T> {
130    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
131      var b = DoubleBox.CreateBuilder();
132      b.Value = ToBoxType(value, mapper);
133      box.SetExtension<DoubleBox>(DoubleBox.Double, b.Build());
134    }
135    protected override T Extract(Box box, Type type, Mapper mapper) {
136      return ToValueType(box.GetExtension(DoubleBox.Double).Value, type, mapper);
137    }
138    protected abstract double ToBoxType(T value, Mapper mapper);
139    protected abstract T ToValueType(double value, Type type, Mapper mapper);
140  }
141  public abstract class StringBoxTransformer<T> : BoxTransformer<T> {
142    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
143      var b = StringBox.CreateBuilder();
144      b.Value = ToBoxType(value, mapper);
145      box.SetExtension<StringBox>(StringBox.String, b.Build());
146    }
147    protected override T Extract(Box box, Type type, Mapper mapper) {
148      return ToValueType(box.GetExtension(StringBox.String).Value, type, mapper);
149    }
150    protected abstract string ToBoxType(T value, Mapper mapper);
151    protected abstract T ToValueType(string value, Type type, Mapper mapper);
152  }
153  public abstract class BytesBoxTransformer<T> : BoxTransformer<T> {
154    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
155      var b = BytesBox.CreateBuilder();
156      b.Value = ByteString.CopyFrom(ToBoxType(value, mapper));
157      box.SetExtension<BytesBox>(BytesBox.Bytes, b.Build());
158    }
159    protected override T Extract(Box box, Type type, Mapper mapper) {
160      return ToValueType(box.GetExtension(BytesBox.Bytes).Value.ToByteArray(), type, mapper);
161    }
162    protected abstract byte[] ToBoxType(T value, Mapper mapper);
163    protected abstract T ToValueType(byte[] value, Type type, Mapper mapper);
164  }
165  #endregion
166
167  #region Array Box Transformers
168  public abstract class ByteArrayBoxTransformer<T> : BoxTransformer<T> {
169    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
170      var b = ByteArrayBox.CreateBuilder();
171      b.SetValues(ToByteString(value));
172      box.SetExtension(ByteArrayBox.ByteArray, b.Build());
173    }
174    protected override T Extract(Box box, Type type, Mapper mapper) {
175      return FromByteString(box.GetExtension(ByteArrayBox.ByteArray).Values);
176    }
177    protected abstract ByteString ToByteString(T value);
178    protected abstract T FromByteString(ByteString byteString);
179  }
180  public abstract class BoolArrayBoxTransformer<T> : BoxTransformer<T> {
181    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
182      var b = BoolArrayBox.CreateBuilder();
183      b.AddRangeValues(ToBoxType(value, mapper));
184      box.SetExtension<BoolArrayBox>(BoolArrayBox.BoolArray, b.Build());
185    }
186    protected override T Extract(Box box, Type type, Mapper mapper) {
187      return ToValueType(box.GetExtension(BoolArrayBox.BoolArray).ValuesList, type, mapper);
188    }
189    protected abstract IEnumerable<bool> ToBoxType(T value, Mapper mapper);
190    protected abstract T ToValueType(IEnumerable<bool> value, Type type, Mapper mapper);
191  }
192  public abstract class IntArrayBoxTransformer<T> : BoxTransformer<T> {
193    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
194      var b = IntArrayBox.CreateBuilder();
195      b.AddRangeValues(ToBoxType(value, mapper));
196      box.SetExtension<IntArrayBox>(IntArrayBox.IntArray, b.Build());
197    }
198    protected override T Extract(Box box, Type type, Mapper mapper) {
199      return ToValueType(box.GetExtension(IntArrayBox.IntArray).ValuesList, type, mapper);
200    }
201    protected abstract IEnumerable<int> ToBoxType(T value, Mapper mapper);
202    protected abstract T ToValueType(IEnumerable<int> value, Type type, Mapper mapper);
203  }
204  public abstract class LongArrayBoxTransformer<T> : BoxTransformer<T> {
205    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
206      var b = LongArrayBox.CreateBuilder();
207      b.AddRangeValues(ToBoxType(value, mapper));
208      box.SetExtension<LongArrayBox>(LongArrayBox.LongArray, b.Build());
209    }
210    protected override T Extract(Box box, Type type, Mapper mapper) {
211      return ToValueType(box.GetExtension(LongArrayBox.LongArray).ValuesList, type, mapper);
212    }
213    protected abstract IEnumerable<long> ToBoxType(T value, Mapper mapper);
214    protected abstract T ToValueType(IEnumerable<long> value, Type type, Mapper mapper);
215  }
216  public abstract class UnsignedIntArrayBoxTransformer<T> : BoxTransformer<T> {
217    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
218      var b = UnsignedIntArrayBox.CreateBuilder();
219      b.AddRangeValues(ToBoxType(value, mapper));
220      box.SetExtension<UnsignedIntArrayBox>(UnsignedIntArrayBox.UnsignedIntArray, b.Build());
221    }
222    protected override T Extract(Box box, Type type, Mapper mapper) {
223      return ToValueType(box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray).ValuesList, type, mapper);
224    }
225    protected abstract IEnumerable<uint> ToBoxType(T value, Mapper mapper);
226    protected abstract T ToValueType(IEnumerable<uint> value, Type type, Mapper mapper);
227  }
228  public abstract class UnsignedLongArrayBoxTransformer<T> : BoxTransformer<T> {
229    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
230      var b = UnsignedLongArrayBox.CreateBuilder();
231      b.AddRangeValues(ToBoxType(value, mapper));
232      box.SetExtension<UnsignedLongArrayBox>(UnsignedLongArrayBox.UnsignedLongArray, b.Build());
233    }
234    protected override T Extract(Box box, Type type, Mapper mapper) {
235      return ToValueType(box.GetExtension(UnsignedLongArrayBox.UnsignedLongArray).ValuesList, type, mapper);
236    }
237    protected abstract IEnumerable<ulong> ToBoxType(T value, Mapper mapper);
238    protected abstract T ToValueType(IEnumerable<ulong> value, Type type, Mapper mapper);
239  }
240  public abstract class FloatArrayBoxTransformer<T> : BoxTransformer<T> {
241    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
242      var b = FloatArrayBox.CreateBuilder();
243      b.AddRangeValues(ToBoxType(value, mapper));
244      box.SetExtension<FloatArrayBox>(FloatArrayBox.FloatArray, b.Build());
245    }
246    protected override T Extract(Box box, Type type, Mapper mapper) {
247      return ToValueType(box.GetExtension(FloatArrayBox.FloatArray).ValuesList, type, mapper);
248    }
249    protected abstract IEnumerable<float> ToBoxType(T value, Mapper mapper);
250    protected abstract T ToValueType(IEnumerable<float> value, Type type, Mapper mapper);
251  }
252  public abstract class DoubleArrayBoxTransformer<T> : BoxTransformer<T> {
253    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
254      var b = DoubleArrayBox.CreateBuilder();
255      b.AddRangeValues(ToBoxType(value, mapper));
256      box.SetExtension<DoubleArrayBox>(DoubleArrayBox.DoubleArray, b.Build());
257    }
258    protected override T Extract(Box box, Type type, Mapper mapper) {
259      return ToValueType(box.GetExtension(DoubleArrayBox.DoubleArray).ValuesList, type, mapper);
260    }
261    protected abstract IEnumerable<double> ToBoxType(T value, Mapper mapper);
262    protected abstract T ToValueType(IEnumerable<double> value, Type type, Mapper mapper);
263  }
264  public abstract class StringArrayBoxTransformer<T> : BoxTransformer<T> {
265    protected override void Populate(Box.Builder box, T value, Mapper mapper) {
266      var b = StringArrayBox.CreateBuilder();
267      b.AddRangeValues(ToBoxType(value, mapper));
268      box.SetExtension<StringArrayBox>(StringArrayBox.StringArray, b.Build());
269    }
270    protected override T Extract(Box box, Type type, Mapper mapper) {
271      return ToValueType(box.GetExtension(StringArrayBox.StringArray).ValuesList, type, mapper);
272    }
273    protected abstract IEnumerable<string> ToBoxType(T value, Mapper mapper);
274    protected abstract T ToValueType(IEnumerable<string> value, Type type, Mapper mapper);
275  }
276  #endregion
277
278  [Transformer("11B822C9-46A0-4B65-AE4A-D12F63DDE9F6", 50)]
279  internal sealed class TypeTransformer : Transformer {
280    public override bool CanTransformType(Type type) {
281      return typeof(Type).IsAssignableFrom(type);
282    }
283    public override Box ToBox(object o, Mapper mapper) {
284      var box = Box.CreateBuilder();
285      box.TransformerId = mapper.GetTransformerId(this);
286      Populate(box, o, mapper);
287      return box.Build();
288    }
289    private void Populate(Box.Builder box, object value, Mapper mapper) {
290      var type = (Type)value;
291      var typeBox = TypeBox.CreateBuilder();
292      if (type.IsGenericType) {
293        box.TypeId = mapper.GetTypeId(type.GetGenericTypeDefinition());
294        typeBox.AddRangeGenericTypeIds(type.GetGenericArguments().Select(t => mapper.GetBoxId(t)));
295      } else if (type.IsArray) {
296        box.TypeId = mapper.GetTypeId(typeof(Array));
297        typeBox.AddGenericTypeIds(mapper.GetBoxId(type.GetElementType()));
298      } else {
299        box.TypeId = mapper.GetTypeId(type);
300      }
301
302      if (StorableTypeAttribute.IsStorableType(type))
303        typeBox.Version = StorableTypeAttribute.GetStorableTypeAttribute(type).Version;
304      box.SetExtension(TypeBox.Type, typeBox.Build());
305    }
306    public override object ToObject(Box box, Mapper mapper) {
307      return Extract(box, mapper.GetType(box.TypeId), mapper);
308    }
309    private object Extract(Box box, Type type, Mapper mapper) {
310      var b = box.GetExtension(TypeBox.Type);
311      if (type.IsGenericType) {
312        return type.MakeGenericType(b.GenericTypeIdsList.Select(id => (Type)mapper.GetObject(id)).ToArray());
313      } else if (type == typeof(Array)) {
314        return ((Type)mapper.GetObject(b.GetGenericTypeIds(0))).MakeArrayType();
315      } else {
316        return type;
317      }
318    }
319  }
320
321  #region Primitive Value Types
322  [Transformer("268617FE-3F0F-4029-8248-EDA420901FB6", 10000)]
323  internal sealed class ObjectTransformer : BoxTransformer<object> {
324    protected override void Populate(Box.Builder box, object value, Mapper mapper) { }
325    protected override object Extract(Box box, Type type, Mapper mapper) { return new object(); }
326  }
327
328  [Transformer("9FA1C6A8-517E-4623-AC1B-7E9AEF6ED13D", 200)]
329  internal sealed class BoolTransformer : BoolBoxTransformer<bool> {
330    protected override bool ToBoxType(bool value, Mapper mapper) { return value; }
331    protected override bool ToValueType(bool value, Type type, Mapper mapper) { return value; }
332  }
333
334  [Transformer("059633E9-12CB-43EC-8544-57746536E281", 201)]
335  internal sealed class ByteTransformer : UnsignedIntBoxTransformer<byte> {
336    protected override uint ToBoxType(byte value, Mapper mapper) { return value; }
337    protected override byte ToValueType(uint value, Type type, Mapper mapper) { return (byte)value; }
338  }
339
340  [Transformer("5DC2F3AC-0852-4B57-A861-D29CC814A94C", 202)]
341  internal sealed class SByteTransformer : IntBoxTransformer<sbyte> {
342    protected override int ToBoxType(sbyte value, Mapper mapper) { return value; }
343    protected override sbyte ToValueType(int value, Type type, Mapper mapper) { return (sbyte)value; }
344  }
345
346  [Transformer("B862E642-A94A-4870-8065-06126A35A9E1", 203)]
347  internal sealed class ShortTransformer : IntBoxTransformer<short> {
348    protected override int ToBoxType(short value, Mapper mapper) { return value; }
349    protected override short ToValueType(int value, Type type, Mapper mapper) { return (short)value; }
350  }
351
352  [Transformer("D1D3062D-F1BB-4189-AE50-D6986E1DEB4E", 204)]
353  internal sealed class UShortTransformer : UnsignedIntBoxTransformer<ushort> {
354    protected override uint ToBoxType(ushort value, Mapper mapper) { return value; }
355    protected override ushort ToValueType(uint value, Type type, Mapper mapper) { return (ushort)value; }
356  }
357
358  [Transformer("6C444645-3062-4D15-AD01-E6E1B0692A2B", 205)]
359  internal sealed class CharTransformer : UnsignedIntBoxTransformer<char> {
360    protected override uint ToBoxType(char value, Mapper mapper) { return value; }
361    protected override char ToValueType(uint value, Type type, Mapper mapper) { return (char)value; }
362  }
363
364  [Transformer("649E73B2-EFA6-4E01-BCB4-4B29D652C9CB", 206)]
365  internal sealed class IntTransformer : IntBoxTransformer<int> {
366    protected override int ToBoxType(int value, Mapper mapper) { return value; }
367    protected override int ToValueType(int value, Type type, Mapper mapper) { return value; }
368  }
369
370  [Transformer("BCF25010-81A2-49BC-88CC-407D3F393D5B", 207)]
371  internal sealed class UIntTransformer : UnsignedIntBoxTransformer<uint> {
372    protected override uint ToBoxType(uint value, Mapper mapper) { return value; }
373    protected override uint ToValueType(uint value, Type type, Mapper mapper) { return value; }
374  }
375
376  [Transformer("B6F6ACAE-755C-47EE-B8BF-7CDECBE19C30", 208)]
377  internal sealed class LongTransformer : LongBoxTransformer<long> {
378    protected override long ToBoxType(long value, Mapper mapper) { return value; }
379    protected override long ToValueType(long value, Type type, Mapper mapper) { return value; }
380  }
381
382  [Transformer("82333ACA-F041-44E0-B365-27C399594BA7", 209)]
383  internal sealed class ULongTransformer : UnsignedLongBoxTransformer<ulong> {
384    protected override ulong ToBoxType(ulong value, Mapper mapper) { return value; }
385    protected override ulong ToValueType(ulong value, Type type, Mapper mapper) { return value; }
386  }
387
388  [Transformer("8FE91ECF-2261-4934-BECD-C38923B7A703", 210)]
389  internal sealed class FloatTransformer : FloatBoxTransformer<float> {
390    protected override float ToBoxType(float value, Mapper mapper) { return value; }
391    protected override float ToValueType(float value, Type type, Mapper mapper) { return value; }
392  }
393
394  [Transformer("070D23EA-7F38-46B7-A667-219BEF914E49", 211)]
395  internal sealed class DoubleTransformer : DoubleBoxTransformer<double> {
396    protected override double ToBoxType(double value, Mapper mapper) { return value; }
397    protected override double ToValueType(double value, Type type, Mapper mapper) { return value; }
398  }
399
400  [Transformer("BA55C7A6-C91E-4351-A889-E4A7E647F16D", 212)]
401  internal sealed class DateTimeTransformer : LongBoxTransformer<DateTime> {
402    protected override long ToBoxType(DateTime value, Mapper mapper) { return value.Ticks; }
403    protected override DateTime ToValueType(long value, Type type, Mapper mapper) { return new DateTime(value); }
404  }
405
406  [Transformer("0C91441B-2D97-432B-B493-D6EC483FC5AD", 213)]
407  internal sealed class TimeSpanTransformer : LongBoxTransformer<TimeSpan> {
408    protected override long ToBoxType(TimeSpan value, Mapper mapper) { return value.Ticks; }
409    protected override TimeSpan ToValueType(long value, Type type, Mapper mapper) { return new TimeSpan(value); }
410  }
411
412  [Transformer("0B540EAC-79AB-40CF-8277-D2C81135FEB6", 214)]
413  internal sealed class ColorTransformers : IntBoxTransformer<Color> {
414    protected override int ToBoxType(Color value, Mapper mapper) { return value.ToArgb(); }
415    protected override Color ToValueType(int value, Type type, Mapper mapper) { return Color.FromArgb(value); }
416  }
417
418  [Transformer("2E6D4A40-B4BE-425F-8E35-2D7C00054639", 215)]
419  internal sealed class PointTransformer : IntArrayBoxTransformer<Point> {
420    protected override IEnumerable<int> ToBoxType(Point value, Mapper mapper) { return new int[] { value.X, value.Y }; }
421    protected override Point ToValueType(IEnumerable<int> value, Type type, Mapper mapper) { return new Point(value.ElementAt(0), value.ElementAt(1)); }
422  }
423
424  [Transformer("97B5CFC8-CDFA-4EB5-B4CD-5B3CFA5CD844", 216)]
425  internal sealed class KeyValuePairTransformer : BoxTransformer<object> {
426    public override bool CanTransformType(Type type) {
427      return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>));
428    }
429    protected override void Populate(Box.Builder box, object value, Mapper mapper) {
430      var b = UnsignedIntArrayBox.CreateBuilder();
431      var type = value.GetType();
432      var pair = new uint[2];
433      pair[0] = mapper.GetBoxId(type.GetProperty("Key").GetValue(value));
434      pair[1] = mapper.GetBoxId(type.GetProperty("Value").GetValue(value));
435      b.AddRangeValues(pair);
436      box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, b.Build());
437    }
438    public override void FillFromBox(object obj, Box box, Mapper mapper) {
439      var b = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
440      var key = mapper.GetObject(b.GetValues(0));
441      var val = mapper.GetObject(b.GetValues(1));
442      var type = obj.GetType();
443      //DataMemberAccessor.GenerateFieldSetter(type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance))(obj, key);
444      //DataMemberAccessor.GenerateFieldSetter(type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance))(obj, val);
445      type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, key);
446      type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, val);
447    }
448    protected override object Extract(Box box, Type type, Mapper mapper) {
449      return Activator.CreateInstance(type);
450    }
451  }
452
453  [Transformer("EBD8BF65-D97D-4FD4-BF4F-9D58A72B6249", 217)]
454  internal sealed class DecimalTransformer : UnsignedIntBoxTransformer<decimal> {
455    protected override uint ToBoxType(decimal value, Mapper mapper) {
456      return mapper.GetStringId(FormatG30(value));
457    }
458    protected override decimal ToValueType(uint value, Type type, Mapper mapper) {
459      var converter = TypeDescriptor.GetConverter(typeof(Font));
460      return ParseG30(mapper.GetString(value));
461    }
462    private static decimal ParseG30(string s) {
463      decimal d;
464      if (decimal.TryParse(s,
465        NumberStyles.AllowDecimalPoint |
466        NumberStyles.AllowExponent |
467        NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d))
468        return d;
469      throw new FormatException(
470        string.Format("Invalid decimal G30 number format \"{0}\" could not be parsed", s));
471    }
472    private static string FormatG30(decimal d) {
473      return d.ToString("g30", CultureInfo.InvariantCulture);
474    }
475  }
476  #endregion
477
478  #region String
479  [Transformer("E75A594C-0034-4DAB-B28E-8F84F9F6DE8D", 218)]
480  internal sealed class StringTransformer : UnsignedIntBoxTransformer<string> {
481    protected override uint ToBoxType(string value, Mapper mapper) { return mapper.GetStringId(value); }
482    protected override string ToValueType(uint value, Type type, Mapper mapper) { return mapper.GetString(value); }
483  }
484  #endregion
485
486  #region Enum
487  [Transformer("93FF076B-BC4B-4C39-8C40-15E004468C98", 219)]
488  internal sealed class EnumTransformer : Transformer {
489    public override bool CanTransformType(Type type) {
490      return typeof(Enum).IsAssignableFrom(type);
491    }
492
493    public override Box ToBox(object o, Mapper mapper) {
494      var boxBuilder = Box.CreateBuilder();
495      var enumBuilder = new UnsignedIntBox.Builder();
496
497      boxBuilder.TransformerId = mapper.GetTransformerId(this);
498      boxBuilder.TypeId = mapper.GetStringId(o.GetType().AssemblyQualifiedName);
499      enumBuilder.Value = mapper.GetStringId(Enum.Format(o.GetType(), o, "G"));
500
501      boxBuilder.SetExtension(UnsignedIntBox.UnsignedInt, enumBuilder.Build());
502      return boxBuilder.Build();
503    }
504
505    public override object ToObject(Box box, Mapper mapper) {
506      uint value = box.GetExtension(UnsignedIntBox.UnsignedInt).Value;
507      return Enum.Parse(Type.GetType(mapper.GetString(box.TypeId)), mapper.GetString(value));
508    }
509  }
510  #endregion
511
512  #region Struct
513  [Transformer("89DAAFC5-726C-48D4-A4E0-2B0D27329642", 220)]
514  internal sealed class StructTransformer : Transformer {
515    public override bool CanTransformType(Type type) {
516      return type.IsValueType && !type.IsPrimitive && !type.IsEnum && type.IsSealed;
517    }
518    public override Box ToBox(object o, Mapper mapper) {
519      var box = Box.CreateBuilder();
520      box.TransformerId = mapper.GetTransformerId(this);
521      Populate(box, o, mapper);
522      return box.Build();
523    }
524    public override object ToObject(Box box, Mapper mapper) {
525      return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper);
526    }
527    private void Populate(Box.Builder box, object value, Mapper mapper) {
528      var b = StorableClassBox.CreateBuilder();
529      var type = value.GetType();
530
531      var components = new Dictionary<uint, uint>();
532      foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
533        var component = mapper.GetBoxId(fieldInfo.GetValue(value));
534        components.Add(mapper.GetStringId(fieldInfo.Name), component);
535      }
536
537      b.AddRangeKeyIds(components.Keys);
538      b.AddRangeValueIds(components.Values);
539
540      box.TypeId = mapper.GetBoxId(type);
541      box.SetExtension(StorableClassBox.StorableClass, b.Build());
542    }
543    private object Extract(Box box, Type type, Mapper mapper) {
544      var data = box.GetExtension(StorableClassBox.StorableClass);
545      var obj = Activator.CreateInstance(type);
546
547      var components = new Dictionary<uint, uint>();
548      for (int i = 0; i < data.KeyIdsList.Count; i++) {
549        components.Add(data.KeyIdsList[i], data.ValueIdsList[i]);
550      }
551
552      foreach (var t in components) {
553        string name = mapper.GetString(t.Key);
554        MemberInfo[] mis = type.GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);       
555        if (mis.Length != 1)
556          throw new Exception("ambiguous struct member name " + name);
557        MemberInfo mi = mis[0];
558        if(StorableAttribute.IsStorable(mi))
559          throw new PersistenceException("Don't use stroable attributes for structs as all fields are serialized automatically.");
560        if (mi.MemberType == MemberTypes.Field)
561          ((FieldInfo)mi).SetValue(obj, mapper.GetObject(t.Value));
562        else
563          throw new Exception("invalid struct member type " + mi.MemberType.ToString());
564      }
565
566      return obj;
567    }
568  }
569  #endregion
570
571  #region Tuple
572  [Transformer("63A19D57-EEEF-4346-9F06-B35B15EBFFA3", 221)]
573  internal sealed class TupleTransformer : Transformer {
574    private static readonly HashSet<Type> supportedTypes = new HashSet<Type> {
575      typeof(Tuple<>), typeof(Tuple<,>), typeof(Tuple<,,>), typeof(Tuple<,,,>),
576      typeof(Tuple<,,,,>), typeof(Tuple<,,,,,>), typeof(Tuple<,,,,,,>), typeof(Tuple<,,,,,,,>)
577    };
578    public override bool CanTransformType(Type type) {
579      return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition());
580    }
581    public override Box ToBox(object o, Mapper mapper) {
582      var box = Box.CreateBuilder();
583      box.TransformerId = mapper.GetTransformerId(this);
584      Populate(box, o, mapper);
585      return box.Build();
586    }
587    private void Populate(Box.Builder box, object value, Mapper mapper) {
588      var type = value.GetType();
589      var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder();
590      for (int i = 1; i <= type.GetGenericArguments().Length; i++) {
591        string name = string.Format("Item{0}", i);
592        uIntArrayBox.AddValues(mapper.GetBoxId(type.GetProperty(name).GetValue(value)));
593      }
594      box.TypeId = mapper.GetBoxId(type);
595      box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build());
596    }
597    public override object ToObject(Box box, Mapper mapper) {
598      var type = (Type)mapper.GetObject(box.TypeId);
599      var defaultValues = type.GetGenericArguments().Select(x =>
600        x.IsValueType ? Activator.CreateInstance(x) : null
601      ).ToArray();
602      return Activator.CreateInstance(type, defaultValues);
603    }
604    public override void FillFromBox(object obj, Box box, Mapper mapper) {
605      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
606      var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject).ToArray();
607      var type = obj.GetType();
608      for (int i = 1; i <= elements.Length; i++) {
609        string name = string.Format("m_Item{0}", i);
610        DataMemberAccessor.GenerateFieldSetter(type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance))(obj, elements[i - 1]);
611      }
612    }
613  }
614  #endregion
615
616  #region Bitmap
617  [Transformer("D0ADB806-2DFD-459D-B5DA-14B5F1152534", 222)]
618  internal sealed class BitmapTransformer : ByteArrayBoxTransformer<Bitmap> {
619    protected override ByteString ToByteString(Bitmap value) {
620      lock (value)
621        using (var ms = new MemoryStream()) {
622          value.Save(ms, ImageFormat.Png);
623          return ByteString.CopyFrom(ms.ToArray());
624        }
625    }
626    protected override Bitmap FromByteString(ByteString byteString) {
627      using (var ms = new MemoryStream()) {
628        ms.Write(byteString.ToArray(), 0, byteString.Length);
629        ms.Seek(0, SeekOrigin.Begin);
630        return new Bitmap(ms);
631      }
632    }
633  }
634  #endregion
635
636  #region Font
637  [Transformer("AFF27987-3301-4D70-9601-EFCA31BDA0DB", 223)]
638  internal sealed class FontTransformer : UnsignedIntArrayBoxTransformer<Font> {
639
640    protected override IEnumerable<uint> ToBoxType(Font value, Mapper mapper) {
641      yield return mapper.GetStringId(GetFontFamilyName(value.FontFamily));
642      yield return mapper.GetBoxId(value.Size);
643      yield return mapper.GetBoxId(value.Style);
644      yield return mapper.GetBoxId(value.Unit);
645      yield return mapper.GetBoxId(value.GdiCharSet);
646      yield return mapper.GetBoxId(value.GdiVerticalFont);
647    }
648    protected override Font ToValueType(IEnumerable<uint> value, Type type, Mapper mapper) {
649      var fontData = value.ToArray();
650      return new Font(
651        GetFontFamily(mapper.GetString(fontData[0])),
652        (float)mapper.GetObject(fontData[1]),
653        (FontStyle)mapper.GetObject(fontData[2]),
654        (GraphicsUnit)mapper.GetObject(fontData[3]),
655        (byte)mapper.GetObject(fontData[4]),
656        (bool)mapper.GetObject(fontData[5])
657      );
658    }
659
660    public const string GENERIC_MONOSPACE_NAME = "_GenericMonospace";
661    public const string GENERIC_SANS_SERIF_NAME = "_GenericSansSerif";
662    public const string GENERIC_SERIF_NAME = "_GenericSerif";
663
664    public static FontFamily GetFontFamily(string name) {
665      if (name == GENERIC_MONOSPACE_NAME) return FontFamily.GenericMonospace;
666      if (name == GENERIC_SANS_SERIF_NAME) return FontFamily.GenericSansSerif;
667      if (name == GENERIC_SERIF_NAME) return FontFamily.GenericSerif;
668      return new FontFamily(name);
669    }
670
671    public static string GetFontFamilyName(FontFamily ff) {
672      if (ff.Equals(FontFamily.GenericMonospace)) return GENERIC_MONOSPACE_NAME;
673      if (ff.Equals(FontFamily.GenericSansSerif)) return GENERIC_SANS_SERIF_NAME;
674      if (ff.Equals(FontFamily.GenericSerif)) return GENERIC_SERIF_NAME;
675      return ff.Name;
676    }
677  }
678  #endregion
679
680  #region Array Types
681  [Transformer("FF89F6D1-CDE3-498E-9166-F70AC6EB01F1", 301)]
682  internal sealed class ByteArrayTransformer : ByteArrayBoxTransformer<byte[]> {
683    protected override ByteString ToByteString(byte[] value) {
684      return ByteString.CopyFrom(value);
685    }
686    protected override byte[] FromByteString(ByteString byteString) {
687      return byteString.ToArray();
688    }
689  }
690
691  [Transformer("B49B3F2D-2E97-4BAB-8705-8D29DA707C6A", 302)]
692  internal sealed class SByteArrayTransformer : ByteArrayBoxTransformer<sbyte[]> {
693    protected override ByteString ToByteString(sbyte[] value) {
694      return ByteString.CopyFrom(value.Select(b => (byte)b).ToArray());
695    }
696    protected override sbyte[] FromByteString(ByteString byteString) {
697      return byteString.Select(b => (sbyte)b).ToArray();
698    }
699  }
700
701  [Transformer("F25A73B2-6B67-4493-BD59-B836AF4455D1", 300)]
702  internal sealed class BoolArrayTransformer : BoolArrayBoxTransformer<bool[]> {
703    protected override IEnumerable<bool> ToBoxType(bool[] value, Mapper mapper) { return value; }
704    protected override bool[] ToValueType(IEnumerable<bool> value, Type type, Mapper mapper) { return value.ToArray(); }
705  }
706
707  [Transformer("2811FDD4-6800-4CBA-86D7-9071ED5775ED", 303)]
708  internal sealed class ShortArrayTransformer : ByteArrayBoxTransformer<short[]> {
709    protected override ByteString ToByteString(short[] value) {
710      var res = new byte[value.Length * 2];
711      for (int i = 0; i < value.Length; i++) {
712        var bytes = BitConverter.GetBytes(value[i]);
713        Array.Copy(bytes, 0, res, i * 2, 2);
714      }
715      return ByteString.CopyFrom(res);
716    }
717    protected override short[] FromByteString(ByteString byteString) {
718      var bytes = byteString.ToArray();
719      var res = new short[bytes.Length / 2];
720      for (int i = 0; i < bytes.Length; i += 2) {
721        res[i / 2] = BitConverter.ToInt16(bytes, i);
722      }
723      return res;
724    }
725  }
726
727  [Transformer("1AAC2625-356C-40BC-8CB4-15CB3D047EB8", 304)]
728  internal sealed class UShortArrayTransformer : ByteArrayBoxTransformer<ushort[]> {
729    protected override ByteString ToByteString(ushort[] value) {
730      var res = new byte[value.Length * 2];
731      for (int i = 0; i < value.Length; i++) {
732        var bytes = BitConverter.GetBytes(value[i]);
733        Array.Copy(bytes, 0, res, i * 2, 2);
734      }
735      return ByteString.CopyFrom(res);
736    }
737    protected override ushort[] FromByteString(ByteString byteString) {
738      var bytes = byteString.ToArray();
739      var res = new ushort[bytes.Length / 2];
740      for (int i = 0; i < bytes.Length; i += 2) {
741        res[i / 2] = BitConverter.ToUInt16(bytes, i);
742      }
743      return res;
744    }
745  }
746
747  [Transformer("12F19098-5D49-4C23-8897-69087F1C146D", 305)]
748  internal sealed class CharArrayTransformer : ByteArrayBoxTransformer<char[]> {
749    protected override ByteString ToByteString(char[] value) {
750      var res = new byte[value.Length * 2];
751      for (int i = 0; i < value.Length; i++) {
752        var bytes = BitConverter.GetBytes(value[i]);
753        Array.Copy(bytes, 0, res, i * 2, 2);
754      }
755      return ByteString.CopyFrom(res);
756    }
757    protected override char[] FromByteString(ByteString byteString) {
758      var bytes = byteString.ToArray();
759      var res = new char[bytes.Length / 2];
760      for (int i = 0; i < bytes.Length; i += 2) {
761        res[i / 2] = BitConverter.ToChar(bytes, i);
762      }
763      return res;
764    }
765  }
766
767  [Transformer("5F6DC3BC-4433-4AE9-A636-4BD126F7DACD", 306)]
768  internal sealed class IntArrayTransformer : IntArrayBoxTransformer<int[]> {
769    protected override IEnumerable<int> ToBoxType(int[] value, Mapper mapper) { return value; }
770    protected override int[] ToValueType(IEnumerable<int> value, Type type, Mapper mapper) { return value.ToArray(); }
771  }
772
773  [Transformer("3F10274F-D350-4C82-89EA-A5EB36D4EFCC", 307)]
774  internal sealed class UIntArrayTransformer : UnsignedIntArrayBoxTransformer<uint[]> {
775    protected override IEnumerable<uint> ToBoxType(uint[] value, Mapper mapper) { return value; }
776    protected override uint[] ToValueType(IEnumerable<uint> value, Type type, Mapper mapper) { return value.ToArray(); }
777  }
778
779  [Transformer("E9D550E2-57F7-47F3-803D-37A619DA1A5C", 308)]
780  internal sealed class LongArrayTransformer : LongArrayBoxTransformer<long[]> {
781    protected override IEnumerable<long> ToBoxType(long[] value, Mapper mapper) { return value; }
782    protected override long[] ToValueType(IEnumerable<long> value, Type type, Mapper mapper) { return value.ToArray(); }
783  }
784
785  [Transformer("C02A205B-2176-4282-AC2B-ADEF96DDBE24", 309)]
786  internal sealed class ULongArrayTransformer : UnsignedLongArrayBoxTransformer<ulong[]> {
787    protected override IEnumerable<ulong> ToBoxType(ulong[] value, Mapper mapper) { return value; }
788    protected override ulong[] ToValueType(IEnumerable<ulong> value, Type type, Mapper mapper) { return value.ToArray(); }
789  }
790
791  [Transformer("3C4590D9-C76E-4AFB-98FD-E50D3D051648", 310)]
792  internal sealed class FloatArrayTransformer : FloatArrayBoxTransformer<float[]> {
793    protected override IEnumerable<float> ToBoxType(float[] value, Mapper mapper) { return value; }
794    protected override float[] ToValueType(IEnumerable<float> value, Type type, Mapper mapper) { return value.ToArray(); }
795  }
796
797  [Transformer("FB98C399-9323-4470-9A85-9186C2B2D5D4", 311)]
798  internal sealed class DoubleArrayTransformer : DoubleArrayBoxTransformer<double[]> {
799    protected override IEnumerable<double> ToBoxType(double[] value, Mapper mapper) { return value; }
800    protected override double[] ToValueType(IEnumerable<double> value, Type type, Mapper mapper) { return value.ToArray(); }
801  }
802
803  [Transformer("68332513-9CF1-47FA-A093-6DDB663186EC", 312)]
804  internal sealed class StringArrayTransformer : StringArrayBoxTransformer<string[]> {
805    protected override IEnumerable<string> ToBoxType(string[] value, Mapper mapper) { return value; }
806    protected override string[] ToValueType(IEnumerable<string> value, Type type, Mapper mapper) { return value.ToArray(); }
807  }
808
809  [Transformer("B01ADF0A-ACAA-444E-9F82-0C7C2AF1F490", 400)]
810  internal sealed class ArrayTransformer : Transformer {
811    public override bool CanTransformType(Type type) {
812      return type.IsArray;
813    }
814    public override Box ToBox(object o, Mapper mapper) {
815      var box = Box.CreateBuilder();
816      box.TransformerId = mapper.GetTransformerId(this);
817      Populate(box, o, mapper);
818      return box.Build();
819    }
820    private void Populate(Box.Builder box, object value, Mapper mapper) {
821      var type = value.GetType();
822      var array = (Array)value;
823      var rank = array.Rank;
824
825      var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder();
826      uIntArrayBox.AddValues(mapper.GetBoxId(rank));
827
828      int[] lengths = new int[rank];
829      int[] lowerBounds = new int[rank];
830      for (int i = 0; i < rank; i++) {
831        lengths[i] = array.GetLength(i);
832        lowerBounds[i] = array.GetLowerBound(i);
833      }
834
835      uIntArrayBox.AddRangeValues(lengths.Select(x => mapper.GetBoxId(x)));
836      uIntArrayBox.AddRangeValues(lowerBounds.Select(x => mapper.GetBoxId(x)));
837
838      int[] positions = (int[])lowerBounds.Clone();
839      while (positions[rank - 1] < lengths[rank - 1] + lowerBounds[rank - 1]) {
840        uIntArrayBox.AddValues(mapper.GetBoxId(array.GetValue(positions)));
841        positions[0] += 1;
842        for (int i = 0; i < rank - 1; i++) {
843          if (positions[i] >= lowerBounds[i] + lengths[i]) {
844            positions[i] = lowerBounds[i];
845            positions[i + 1] += 1;
846          } else {
847            break;
848          }
849        }
850      }
851
852      box.TypeId = mapper.GetBoxId(type);
853      box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build());
854    }
855    public override object ToObject(Box box, Mapper mapper) {
856      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
857      var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0));
858
859      int[] lengths = new int[rank], lowerBounds = new int[rank];
860      for (int i = 0; i < rank; i++)
861        lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1));
862      for (int i = 0; i < rank; i++)
863        lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank));
864
865      var type = (Type)mapper.GetObject(box.TypeId);
866      return Array.CreateInstance(type.GetElementType(), lengths, lowerBounds);
867    }
868    public override void FillFromBox(object obj, Box box, Mapper mapper) {
869      var array = (Array)obj;
870      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
871      var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0));
872
873      int[] lengths = new int[rank], lowerBounds = new int[rank];
874      for (int i = 0; i < rank; i++)
875        lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1));
876      for (int i = 0; i < rank; i++)
877        lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank));
878
879      int[] positions = (int[])lowerBounds.Clone();
880      var e = uIntArrayBox.ValuesList.Skip(1 + 2 * rank).GetEnumerator();
881      while (e.MoveNext()) {
882        int[] currentPositions = positions;
883        array.SetValue(mapper.GetObject(e.Current), currentPositions);
884        positions[0] += 1;
885        for (int i = 0; i < rank - 1; i++) {
886          if (positions[i] >= lengths[i] + lowerBounds[i]) {
887            positions[i] = lowerBounds[i];
888            positions[i + 1] += 1;
889          } else {
890            break;
891          }
892        }
893      }
894    }
895  }
896  #endregion
897
898  [Transformer("4FA5EAAF-ECC7-4A9C-84E7-6583DA96F3B9", 500)]
899  internal sealed class EnumerableTransformer : Transformer {
900    private static readonly HashSet<Type> supportedTypes = new HashSet<Type> {
901      typeof(Stack<>), typeof(Stack),
902      typeof(Queue<>), typeof(Queue),
903      typeof(HashSet<>),
904      typeof(List<>), typeof(ArrayList)
905    };
906    public override bool CanTransformType(Type type) {
907      return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition()) || supportedTypes.Contains(type);
908    }
909    public override Box ToBox(object o, Mapper mapper) {
910      var box = Box.CreateBuilder();
911      box.TransformerId = mapper.GetTransformerId(this);
912      Populate(box, o, mapper);
913      return box.Build();
914    }
915    private void Populate(Box.Builder box, object value, Mapper mapper) {
916      var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder();
917
918      var type = value.GetType();
919      var propertyInfo = type.GetProperty("Comparer");
920      if (propertyInfo != null) {
921        // TODO: where to store id for comparer box? (atm: first element in int array ...)
922        var comparer = propertyInfo.GetValue(value);
923        var comparerType = comparer.GetType();
924        if (Default.CompositeSerializers.Storable.StorableTypeAttribute.IsStorableType(comparerType))
925          uIntArrayBox.AddValues(mapper.GetBoxId(comparer));
926        else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
927          throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
928        else
929          uIntArrayBox.AddValues(mapper.GetBoxId(comparerType));
930      }
931
932      foreach (var item in (IEnumerable)value)
933        uIntArrayBox.AddValues(mapper.GetBoxId(item));
934
935      box.TypeId = mapper.GetBoxId(type);
936      box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build());
937    }
938    public override object ToObject(Box box, Mapper mapper) {
939      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
940      var type = (Type)mapper.GetObject(box.TypeId);
941      return Activator.CreateInstance(type);
942    }
943    public override void FillFromBox(object obj, Box box, Mapper mapper) {
944      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
945      var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject);
946      var type = obj.GetType();
947
948      string methodName = string.Empty;
949      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Stack<>) || type == typeof(Stack)) {
950        elements = elements.Reverse();
951        methodName = "Push";
952      } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Queue<>) || type == typeof(Queue)) {
953        methodName = "Enqueue";
954      } else {
955        methodName = "Add";
956        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) {
957          var fieldInfo = type.GetField("m_comparer", BindingFlags.NonPublic | BindingFlags.Instance);
958          var comparerObj = mapper.GetObject(uIntArrayBox.GetValues(0));
959          var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj;
960          fieldInfo.SetValue(obj, comparer);
961          elements = elements.Skip(1);
962        }
963      }
964
965      MethodInfo addMethod = type.GetMethod(methodName);
966      foreach (var e in elements)
967        addMethod.Invoke(obj, new[] { e });
968    }
969  }
970
971  [Transformer("C47A62F5-F113-4A43-A8EE-CF817EC799A2", 501)]
972  internal sealed class DictionaryTransformer : Transformer {
973    public override bool CanTransformType(Type type) {
974      return type.IsGenericType && typeof(Dictionary<,>) == type.GetGenericTypeDefinition();
975    }
976    public override Box ToBox(object o, Mapper mapper) {
977      var box = Box.CreateBuilder();
978      box.TransformerId = mapper.GetTransformerId(this);
979      Populate(box, o, mapper);
980      return box.Build();
981    }
982    private void Populate(Box.Builder box, object value, Mapper mapper) {
983      var dictionaryBox = DictionaryBox.CreateBuilder();
984      foreach (DictionaryEntry item in (IDictionary)value) {
985        dictionaryBox.AddKeyIds(mapper.GetBoxId(item.Key));
986        dictionaryBox.AddValueIds(mapper.GetBoxId(item.Value));
987      }
988
989      var type = value.GetType();
990      var propertyInfo = type.GetProperty("Comparer");
991      var comparer = propertyInfo.GetValue(value);
992
993      var comparerType = comparer.GetType();
994      if (Default.CompositeSerializers.Storable.StorableTypeAttribute.IsStorableType(comparerType))
995        dictionaryBox.SetComparerId(mapper.GetBoxId(comparer));
996      else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
997        throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
998      else
999        dictionaryBox.SetComparerId(mapper.GetBoxId(comparerType));
1000
1001      box.TypeId = mapper.GetBoxId(type);
1002      box.SetExtension(DictionaryBox.Dictionary, dictionaryBox.Build());
1003    }
1004    public override object ToObject(Box box, Mapper mapper) {
1005      var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary);
1006      return Activator.CreateInstance((Type)mapper.GetObject(box.TypeId), dictionaryBox.ValueIdsCount);
1007    }
1008    public override void FillFromBox(object obj, Box box, Mapper mapper) {
1009      var type = obj.GetType();
1010      var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary);
1011      var comparerObj = mapper.GetObject(dictionaryBox.ComparerId);
1012      var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj;
1013
1014      var fieldInfo = type.GetField("comparer", BindingFlags.NonPublic | BindingFlags.Instance);
1015      fieldInfo.SetValue(obj, comparer);
1016
1017
1018      var addMethod = type.GetMethod("Add");
1019      for (int i = 0; i < dictionaryBox.KeyIdsCount; i++) {
1020        var key = mapper.GetObject(dictionaryBox.GetKeyIds(i));
1021        var value = mapper.GetObject(dictionaryBox.GetValueIds(i));
1022        addMethod.Invoke(obj, new[] { key, value });
1023      }
1024    }
1025  }
1026}
Note: See TracBrowser for help on using the repository browser.