This repository has been archived by the owner on May 25, 2021. It is now read-only.
/
DynamicCompositeTypeConverter.cs
128 lines (100 loc) · 3.18 KB
/
DynamicCompositeTypeConverter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace FluentCassandra.Types
{
internal class DynamicCompositeTypeConverter : CassandraObjectConverter<List<CassandraObject>>
{
private readonly IDictionary<char, CassandraType> _aliases;
public DynamicCompositeTypeConverter(IDictionary<char, CassandraType> aliases)
{
this._aliases = aliases;
}
public override bool CanConvertFrom(Type sourceType)
{
return sourceType == typeof(byte[]) || sourceType.GetInterfaces().Contains(typeof(IEnumerable<CassandraObject>));
}
public override bool CanConvertTo(Type destinationType)
{
return destinationType == typeof(byte[]) || destinationType == typeof(List<CassandraObject>) || destinationType == typeof(CassandraObject[]) || destinationType == typeof(string);
}
public override List<CassandraObject> ConvertFromInternal(object value)
{
if (value is byte[])
{
var components = new List<CassandraObject>();
using (var bytes = new MemoryStream((byte[])value))
{
while (true)
{
if (bytes.ReadByte() != 1)
break; // we don't yet support full comparator names
var aliasType = (char)bytes.ReadByte();
var type = _aliases[aliasType];
// value length
var byteLength = new byte[2];
if (bytes.Read(byteLength, 0, 2) <= 0)
break;
// value
var length = BitConverter.ToUInt16(byteLength, 0);
var buffer = new byte[length];
bytes.Read(buffer, 0, length);
components.Add(CassandraObject.GetCassandraObjectFromObject(buffer, type));
// end of component
if (bytes.ReadByte() != 0)
break;
}
}
return components;
}
if (value.GetType().GetInterfaces().Contains(typeof(IEnumerable<CassandraObject>)))
return new List<CassandraObject>((IEnumerable<CassandraObject>)value);
return null;
}
public override object ConvertToInternal(List<CassandraObject> value, Type destinationType)
{
if (!(value is List<CassandraObject>))
return null;
if (destinationType == typeof(string))
return String.Join(":", (IEnumerable<CassandraObject>)value);
if (destinationType == typeof(byte[]))
{
var components = value;
using (var bytes = new MemoryStream())
{
foreach (var c in components)
{
var b = (byte[])c;
var length = (ushort)b.Length;
// comparator part
bytes.WriteByte((byte)1);
bytes.WriteByte((byte)_aliases.FirstOrDefault(x => x.Value.FluentType == c.GetType()).Key);
// value length
bytes.Write(BitConverter.GetBytes(length), 0, 2);
// value
bytes.Write(b, 0, length);
// end of component
bytes.WriteByte((byte)0);
}
return bytes.ToArray();
}
}
if (destinationType == typeof(CassandraObject[]))
return value.ToArray();
if (destinationType == typeof(List<CassandraObject>))
return value;
return null;
}
public override byte[] ToBigEndian(List<CassandraObject> value)
{
var bytes = ConvertTo<byte[]>(value);
return bytes;
}
public override List<CassandraObject> FromBigEndian(byte[] value)
{
var obj = ConvertFromInternal(value);
return obj;
}
}
}