1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
7 using System
.Collections
.Generic
;
8 using System
.Reflection
;
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
)
22 for (int i
= 0 ; i
!= a
.data
.Length
; i
++)
23 if (a
.data
[i
] != b
.data
[i
])
29 public static bool operator != (Signature a
, Signature b
)
34 public override bool Equals (object o
)
39 if (!(o
is Signature
))
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
];
92 //TODO: this should be private, but MessageWriter and Monitor still use it
94 public byte[] GetBuffer ()
99 internal DType
this[int index
]
102 return (DType
)data
[index
];
117 return Encoding
.ASCII
.GetString (data
);
121 public override string ToString ()
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
)
140 sig
+= new Signature (DType
.StructEnd
);
145 public static Signature
MakeDictEntry (Signature keyType
, Signature valueType
)
147 Signature sig
= Signature
.Empty
;
149 sig
+= new Signature (DType
.DictEntryBegin
);
154 sig
+= new Signature (DType
.DictEntryEnd
);
159 public static Signature
MakeDict (Signature keyType
, Signature valueType
)
161 return MakeDictEntry (keyType
, valueType
).MakeArraySignature ();
173 if (this[2] != DType
.DictEntryBegin
)
186 if (this[0] != DType
.Array
)
193 public Signature
GetElementSignature ()
196 throw new Exception ("Cannot get the element signature of a non-array (signature was '" + this + "')");
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 ()
215 Type ret
= ToType (ref pos
);
216 if (pos
!= data
.Length
)
217 throw new Exception ("Signature '" + Value
+ "' is not a single complete type");
221 internal static DType
TypeCodeToDType (TypeCode typeCode
)
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
;
241 case TypeCode
.UInt16
:
245 case TypeCode
.UInt32
:
249 case TypeCode
.UInt64
:
251 case TypeCode
.Single
:
253 case TypeCode
.Double
:
255 case TypeCode
.Decimal
:
256 return DType
.Invalid
;
257 case TypeCode
.DateTime
:
258 return DType
.Invalid
;
259 case TypeCode
.String
:
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))
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
));
288 return TypeToDType (Enum
.GetUnderlyingType (type
));
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
)
302 //TODO: maybe throw an exception here
303 return DType
.Invalid
;
306 public Type
ToType (ref int pos
)
308 DType dtype
= (DType
)data
[pos
++];
312 return typeof (void);
314 return typeof (byte);
316 return typeof (bool);
318 return typeof (short);
320 return typeof (ushort);
324 return typeof (uint);
326 return typeof (long);
328 return typeof (ulong);
329 case DType
.Single
: ////not supported by libdbus at time of writing
330 return typeof (float);
332 return typeof (double);
334 return typeof (string);
335 case DType
.ObjectPath
:
336 return typeof (ObjectPath
);
337 case DType
.Signature
:
338 return typeof (Signature
);
340 //peek to see if this is in fact a dictionary
341 if ((DType
)data
[pos
] == DType
.DictEntryBegin
) {
344 Type keyType
= ToType (ref pos
);
345 Type valueType
= ToType (ref 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}
);
353 return ToType (ref pos
).MakeArrayType ();
356 return typeof (ValueType
);
357 case DType
.DictEntry
:
358 return typeof (System
.Collections
.Generic
.KeyValuePair
<,>);
360 return typeof (object);
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
)
374 throw new ArgumentNullException ("types");
376 Signature sig
= Signature
.Empty
;
378 foreach (Type type
in types
)
379 sig
+= GetSig (type
);
384 public static Signature
GetSig (Type type
)
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
);
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
);
438 public enum DType
: byte
440 Invalid
= (byte)'\0',
453 ObjectPath
= (byte)'o',
454 Signature
= (byte)'g',
460 StructBegin
= (byte)'(',
461 StructEnd
= (byte)')',
463 DictEntry
= (byte)'e',
464 DictEntryBegin
= (byte)'{',
465 DictEntryEnd
= (byte)'}',