MessageReader is half-gone from versaplexd/t/*.cs.
[versaplex.git] / dbus-sharp / Signature.cs
blobe52fbad6fe5d8890457de18561bd6b01fbd798c2
1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
4 //
5 using System;
6 using System.Text;
7 using System.Collections.Generic;
8 using System.Reflection;
10 namespace Wv
12 public struct Signature
14 public static readonly Signature Empty
15 = new Signature (String.Empty);
17 public static bool operator == (Signature a, Signature b)
19 if (a.data.Length != b.data.Length)
20 return false;
22 for (int i = 0 ; i != a.data.Length ; i++)
23 if (a.data[i] != b.data[i])
24 return false;
26 return true;
29 public static bool operator != (Signature a, Signature b)
31 return !(a == b);
34 public override bool Equals (object o)
36 if (o == null)
37 return false;
39 if (!(o is Signature))
40 return false;
42 return this == (Signature)o;
45 public override int GetHashCode ()
47 return data.GetHashCode ();
50 public static Signature operator + (Signature s1, Signature s2)
52 return Concat (s1, s2);
55 //these need to be optimized
56 public static Signature Concat (Signature s1, Signature s2)
58 return new Signature (s1.Value + s2.Value);
61 public static Signature Copy (Signature sig)
63 return new Signature (sig.data);
66 public Signature (string value)
68 this.data = Encoding.ASCII.GetBytes (value);
71 public Signature (byte[] value)
73 this.data = (byte[])value.Clone ();
76 //this will become obsolete soon
77 internal Signature (DType value)
79 this.data = new byte[] {(byte)value};
82 internal Signature (DType[] value)
84 this.data = new byte[value.Length];
86 for (int i = 0 ; i != value.Length ; i++)
87 this.data[i] = (byte)value[i];
90 byte[] data;
92 //TODO: this should be private, but MessageWriter and Monitor still use it
93 //[Obsolete]
94 public byte[] GetBuffer ()
96 return data;
99 internal DType this[int index]
101 get {
102 return (DType)data[index];
106 public int Length
108 get {
109 return data.Length;
113 //[Obsolete]
114 public string Value
116 get {
117 return Encoding.ASCII.GetString (data);
121 public override string ToString ()
123 return Value;
126 public Signature MakeArraySignature ()
128 return new Signature (DType.Array) + this;
131 public static Signature MakeStruct (params Signature[] elems)
133 Signature sig = Signature.Empty;
135 sig += new Signature (DType.StructBegin);
137 foreach (Signature elem in elems)
138 sig += elem;
140 sig += new Signature (DType.StructEnd);
142 return sig;
145 public static Signature MakeDictEntry (Signature keyType, Signature valueType)
147 Signature sig = Signature.Empty;
149 sig += new Signature (DType.DictEntryBegin);
151 sig += keyType;
152 sig += valueType;
154 sig += new Signature (DType.DictEntryEnd);
156 return sig;
159 public static Signature MakeDict (Signature keyType, Signature valueType)
161 return MakeDictEntry (keyType, valueType).MakeArraySignature ();
164 public bool IsDict
166 get {
167 if (Length < 3)
168 return false;
170 if (!IsArray)
171 return false;
173 if (this[2] != DType.DictEntryBegin)
174 return false;
176 return true;
180 public bool IsArray
182 get {
183 if (Length < 2)
184 return false;
186 if (this[0] != DType.Array)
187 return false;
189 return true;
193 public Signature GetElementSignature ()
195 if (!IsArray)
196 throw new Exception ("Cannot get the element signature of a non-array (signature was '" + this + "')");
198 //TODO: improve this
199 if (Length != 2)
200 throw new NotSupportedException ("Parsing signatures with more than one primitive value is not supported (signature was '" + this + "')");
202 return new Signature (this[1]);
205 public Type[] ToTypes ()
207 List<Type> types = new List<Type> ();
208 for (int i = 0 ; i != data.Length ; types.Add (ToType (ref i)));
209 return types.ToArray ();
212 public Type ToType ()
214 int pos = 0;
215 Type ret = ToType (ref pos);
216 if (pos != data.Length)
217 throw new Exception ("Signature '" + Value + "' is not a single complete type");
218 return ret;
221 internal static DType TypeCodeToDType (TypeCode typeCode)
223 switch (typeCode)
225 case TypeCode.Empty:
226 return DType.Invalid;
227 case TypeCode.Object:
228 return DType.Invalid;
229 case TypeCode.DBNull:
230 return DType.Invalid;
231 case TypeCode.Boolean:
232 return DType.Boolean;
233 case TypeCode.Char:
234 return DType.UInt16;
235 case TypeCode.SByte:
236 return DType.Byte;
237 case TypeCode.Byte:
238 return DType.Byte;
239 case TypeCode.Int16:
240 return DType.Int16;
241 case TypeCode.UInt16:
242 return DType.UInt16;
243 case TypeCode.Int32:
244 return DType.Int32;
245 case TypeCode.UInt32:
246 return DType.UInt32;
247 case TypeCode.Int64:
248 return DType.Int64;
249 case TypeCode.UInt64:
250 return DType.UInt64;
251 case TypeCode.Single:
252 return DType.Single;
253 case TypeCode.Double:
254 return DType.Double;
255 case TypeCode.Decimal:
256 return DType.Invalid;
257 case TypeCode.DateTime:
258 return DType.Invalid;
259 case TypeCode.String:
260 return DType.String;
261 default:
262 return DType.Invalid;
266 //FIXME: this method is bad, get rid of it
267 internal static DType TypeToDType (Type type)
269 if (type == typeof (void))
270 return DType.Invalid;
272 if (type == typeof (string))
273 return DType.String;
275 if (type == typeof (ObjectPath))
276 return DType.ObjectPath;
278 if (type == typeof (Signature))
279 return DType.Signature;
281 if (type == typeof (object))
282 return DType.Variant;
284 if (type.IsPrimitive)
285 return TypeCodeToDType (Type.GetTypeCode (type));
287 if (type.IsEnum)
288 return TypeToDType (Enum.GetUnderlyingType (type));
290 //needs work
291 if (type.IsArray)
292 return DType.Array;
294 //if (type.UnderlyingSystemType != null)
295 // return TypeToDType (type.UnderlyingSystemType);
296 if (Mapper.IsPublic (type))
297 return DType.ObjectPath;
299 if (!type.IsPrimitive && !type.IsEnum)
300 return DType.Struct;
302 //TODO: maybe throw an exception here
303 return DType.Invalid;
306 public Type ToType (ref int pos)
308 DType dtype = (DType)data[pos++];
310 switch (dtype) {
311 case DType.Invalid:
312 return typeof (void);
313 case DType.Byte:
314 return typeof (byte);
315 case DType.Boolean:
316 return typeof (bool);
317 case DType.Int16:
318 return typeof (short);
319 case DType.UInt16:
320 return typeof (ushort);
321 case DType.Int32:
322 return typeof (int);
323 case DType.UInt32:
324 return typeof (uint);
325 case DType.Int64:
326 return typeof (long);
327 case DType.UInt64:
328 return typeof (ulong);
329 case DType.Single: ////not supported by libdbus at time of writing
330 return typeof (float);
331 case DType.Double:
332 return typeof (double);
333 case DType.String:
334 return typeof (string);
335 case DType.ObjectPath:
336 return typeof (ObjectPath);
337 case DType.Signature:
338 return typeof (Signature);
339 case DType.Array:
340 //peek to see if this is in fact a dictionary
341 if ((DType)data[pos] == DType.DictEntryBegin) {
342 //skip over the {
343 pos++;
344 Type keyType = ToType (ref pos);
345 Type valueType = ToType (ref pos);
346 //skip over the }
347 pos++;
348 //return typeof (IDictionary<,>).MakeGenericType (new Type[] {keyType, valueType});
349 //workaround for Mono bug #81035 (memory leak)
350 return Mapper.GetGenericType (typeof (IDictionary<,>), new Type[] {keyType, valueType});
352 else {
353 return ToType (ref pos).MakeArrayType ();
355 case DType.Struct:
356 return typeof (ValueType);
357 case DType.DictEntry:
358 return typeof (System.Collections.Generic.KeyValuePair<,>);
359 case DType.Variant:
360 return typeof (object);
361 default:
362 throw new NotSupportedException ("Parsing or converting this signature is not yet supported (signature was '" + this + "'), at DType." + dtype);
366 public static Signature GetSig (object[] objs)
368 return GetSig (Type.GetTypeArray (objs));
371 public static Signature GetSig (Type[] types)
373 if (types == null)
374 throw new ArgumentNullException ("types");
376 Signature sig = Signature.Empty;
378 foreach (Type type in types)
379 sig += GetSig (type);
381 return sig;
384 public static Signature GetSig (Type type)
386 if (type == null)
387 throw new ArgumentNullException ("type");
389 //this is inelegant, but works for now
390 if (type == typeof (Signature))
391 return new Signature (DType.Signature);
393 if (type == typeof (ObjectPath))
394 return new Signature (DType.ObjectPath);
396 if (type == typeof (void))
397 return Signature.Empty;
399 if (type == typeof (string))
400 return new Signature (DType.String);
402 if (type == typeof (object))
403 return new Signature (DType.Variant);
405 if (type.IsArray)
406 return GetSig (type.GetElementType ()).MakeArraySignature ();
408 if (type.IsGenericType && (type.GetGenericTypeDefinition () == typeof (IDictionary<,>) || type.GetGenericTypeDefinition () == typeof (Dictionary<,>))) {
410 Type[] genArgs = type.GetGenericArguments ();
411 return Signature.MakeDict (GetSig (genArgs[0]), GetSig (genArgs[1]));
414 if (Mapper.IsPublic (type)) {
415 return new Signature (DType.ObjectPath);
418 if (!type.IsPrimitive && !type.IsEnum) {
419 Signature sig = Signature.Empty;
421 foreach (FieldInfo fi in type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
422 sig += GetSig (fi.FieldType);
424 return Signature.MakeStruct (sig);
427 DType dtype = Signature.TypeToDType (type);
428 return new Signature (dtype);
432 enum ArgDirection
435 Out,
438 public enum DType : byte
440 Invalid = (byte)'\0',
442 Byte = (byte)'y',
443 Boolean = (byte)'b',
444 Int16 = (byte)'n',
445 UInt16 = (byte)'q',
446 Int32 = (byte)'i',
447 UInt32 = (byte)'u',
448 Int64 = (byte)'x',
449 UInt64 = (byte)'t',
450 Single = (byte)'f',
451 Double = (byte)'d',
452 String = (byte)'s',
453 ObjectPath = (byte)'o',
454 Signature = (byte)'g',
456 Array = (byte)'a',
457 Variant = (byte)'v',
459 Struct = (byte)'r',
460 StructBegin = (byte)'(',
461 StructEnd = (byte)')',
463 DictEntry = (byte)'e',
464 DictEntryBegin = (byte)'{',
465 DictEntryEnd = (byte)'}',