diff --git a/src/ExportObject.cs b/src/ExportObject.cs index 18939ad..06f25f7 100644 --- a/src/ExportObject.cs +++ b/src/ExportObject.cs @@ -14,10 +14,82 @@ namespace DBus { using Protocol; - internal class PropertyCallers { - public Type Type { get; set; } + internal class PropertyCall { public MethodCaller Get { get; set; } public MethodCaller Set { get; set; } + public PropertyInfo MetaData { get; set; } + } + + internal class MethodCall { + public Signature Out { get; set; } + public Signature In { get; set; } + public MethodCaller Call { get; set; } + public MethodInfo MetaData { get; set; } + } + + internal class MethodDictionary : Dictionary { } + internal class PropertyDictionary : Dictionary { } + + internal class InterfaceMethods : Dictionary { } + internal class InterfaceProperties : Dictionary { } + + internal class DBusMemberTable { + + public Type ObjectType { get; private set; } + + public DBusMemberTable(Type type) + { + ObjectType = type; + } + + InterfaceMethods Methods = new InterfaceMethods(); + InterfaceProperties Properties = new InterfaceProperties(); + + public MethodCall GetMethodCall (string iface, string name) + { + return Lookup ( + Methods, + iface, + name, + (i, n) => { + Type it = Mapper.GetInterfaceType (ObjectType, i); + MethodInfo mi = it.GetMethod (n); + return TypeImplementer.GenMethodCall (mi); + } + ); + } + + public PropertyCall GetPropertyCall (string iface, string name) + { + return Lookup ( + Properties, + iface, + name, + (i, n) => { + Type it = Mapper.GetInterfaceType(ObjectType, i); + PropertyInfo pi = it.GetProperty(n); + return TypeImplementer.GenPropertyCall (pi); + } + ); + } + + private static V Lookup (TMap1 map, A k1, B k2, Func factory) + where TMap2 : IDictionary, new() + where TMap1 : IDictionary + { + TMap2 first; + if (!map.TryGetValue (k1, out first)) { + map [k1] = first = new TMap2 (); + } + + V value; + if (!first.TryGetValue (k2, out value)) { + first [k2] = value = factory (k1, k2); + } + + return value; + } + } //TODO: perhaps ExportObject should not derive from BusObject @@ -27,13 +99,7 @@ internal class ExportObject : BusObject, IDisposable //it's a bit silly as a property bool isRegistered = false; - Dictionary propertyInfoCache = new Dictionary (); - - Dictionary methodInfoCache = new Dictionary (); - - static readonly Dictionary mCallers = new Dictionary (); - - static readonly Dictionary pCallers = new Dictionary (); + static readonly Dictionary typeMembers = new Dictionary(); public ExportObject (Connection conn, ObjectPath object_path, object obj) : base (conn, null, object_path) { @@ -75,26 +141,16 @@ internal virtual void WriteIntrospect (Introspector intro) intro.WriteType (Object.GetType ()); } - internal static MethodCaller GetMCaller (MethodInfo mi) - { - MethodCaller mCaller; - if (!mCallers.TryGetValue (mi, out mCaller)) { - mCaller = TypeImplementer.GenCaller (mi); - mCallers[mi] = mCaller; - } - return mCaller; - } - public static ExportObject CreateExportObject (Connection conn, ObjectPath object_path, object obj) { + Type type = obj.GetType (); + DBusMemberTable table; + if (!typeMembers.TryGetValue (type, out table)) { + typeMembers [type] = new DBusMemberTable (type); + } return new ExportObject (conn, object_path, obj); } - private static string Key (string iface, string member) - { - return string.Format ("{0}.{1}", iface, member); - } - public virtual void HandleMethodCall (MessageContainer method_call) { switch (method_call.Interface) { @@ -103,26 +159,23 @@ public virtual void HandleMethodCall (MessageContainer method_call) return; } - var cache_key = Key (method_call.Interface, method_call.Member); - MethodInfo mi; - if (!methodInfoCache.TryGetValue (cache_key, out mi)) { - mi = Mapper.GetMethod (Object.GetType (), method_call); - methodInfoCache [cache_key] = mi; + MethodCall mCaller = null; + + try { + mCaller = typeMembers[Object.GetType()].GetMethodCall( + method_call.Interface, + method_call.Member + ); } + catch { /* No Such Member */ } - if (mi == null) { + if (mCaller == null) { conn.MaybeSendUnknownMethodError (method_call); return; } - MethodCaller mCaller; - if (!mCallers.TryGetValue (mi, out mCaller)) { - mCaller = TypeImplementer.GenCaller (mi); - mCallers[mi] = mCaller; - } - - Signature inSig, outSig; - TypeImplementer.SigsForMethod (mi, out inSig, out outSig); + Signature inSig = mCaller.In, + outSig = mCaller.Out; Message msg = method_call.Message; MessageReader msgReader = new MessageReader (msg); @@ -130,12 +183,12 @@ public virtual void HandleMethodCall (MessageContainer method_call) Exception raisedException = null; try { - mCaller (Object, msgReader, msg, retWriter); + mCaller.Call (Object, msgReader, msg, retWriter); } catch (Exception e) { raisedException = e; } - IssueReply (method_call, outSig, retWriter, mi, raisedException); + IssueReply (method_call, outSig, retWriter, mCaller.MetaData, raisedException); } private void IssueReply (MessageContainer method_call, Signature outSig, MessageWriter retWriter, MethodInfo mi, Exception raisedException) @@ -183,31 +236,41 @@ private void HandlePropertyCall (MessageContainer method_call) object[] args = MessageHelper.GetDynamicValues (msg); string face = (string) args [0]; + + if ("GetAll" == method_call.Member) { + // TODO + throw new NotImplementedException (); + } + string name = (string) args [1]; - PropertyInfo p = GetPropertyInfo (Object.GetType (), face, name); - PropertyCallers pcs = GetPropertyCallers (p); + PropertyCall pcs = typeMembers[Object.GetType()].GetPropertyCall ( + face, + name + ); - MethodCaller pc; MethodInfo mi; + MethodCaller pc; + Signature outSig, inSig = method_call.Signature; switch (method_call.Member) { case "Set": + mi = pcs.MetaData.GetSetMethod (); pc = pcs.Set; - mi = p.GetSetMethod (); + outSig = Signature.Empty; break; case "Get": + mi = pcs.MetaData.GetGetMethod (); pc = pcs.Get; - mi = p.GetGetMethod (); + outSig = Signature.GetSig(mi.ReturnType); break; - case "GetAll": - throw new NotImplementedException (); default: throw new ArgumentException (string.Format ("No such method {0}.{1}", method_call.Interface, method_call.Member)); } - if (null == pc || null == mi) { - throw new MissingMethodException (); + if (null == pc) { + conn.MaybeSendUnknownMethodError (method_call); + return; } Exception raised = null; @@ -217,35 +280,9 @@ private void HandlePropertyCall (MessageContainer method_call) raised = e; } - Signature inSig, outSig; - TypeImplementer.SigsForMethod (mi, out inSig, out outSig); - IssueReply (method_call, outSig, retWriter, mi, raised); } - private PropertyInfo GetPropertyInfo (Type type, string @interface, string property) - { - var key = Key (@interface, property); - PropertyInfo pi; - if (!propertyInfoCache.TryGetValue (key, out pi)) { - pi = Mapper.GetPublicProperties(Mapper.GetInterfaceType (type, @interface)).First (x => property == x.Name); - propertyInfoCache [key] = pi; - } - - return pi; - } - - private static PropertyCallers GetPropertyCallers (PropertyInfo pi) - { - PropertyCallers pCaller; - if (!pCallers.TryGetValue (pi, out pCaller)) { - pCaller = TypeImplementer.GenPropertyCallers (pi); - pCallers[pi] = pCaller; - } - - return pCaller; - } - public object Object { get; private set; diff --git a/src/TypeImplementer.cs b/src/TypeImplementer.cs index e13433b..f67a7af 100644 --- a/src/TypeImplementer.cs +++ b/src/TypeImplementer.cs @@ -514,18 +514,30 @@ internal static MethodInfo GetReadMethod (Type t) return null; } - internal static PropertyCallers GenPropertyCallers (PropertyInfo target) + internal static MethodCall GenMethodCall (MethodInfo target) { - var pc = new PropertyCallers { - Type = target.PropertyType, - Get = GenGetMethod (target), - Set = GenSetMethod (target) + Signature inSig, outSig; + SigsForMethod (target, out inSig, out outSig); + return new MethodCall { + Out = outSig, + In = inSig, + Call = GenCaller (target), + MetaData = target + }; + } + + internal static PropertyCall GenPropertyCall (PropertyInfo target) + { + var pc = new PropertyCall { + Get = GenGetCall (target), + Set = GenSetCall (target), + MetaData = target }; return pc; } - internal static MethodCaller GenGetMethod (PropertyInfo target) + internal static MethodCaller GenGetCall (PropertyInfo target) { var mi = target.GetGetMethod (); @@ -533,15 +545,20 @@ internal static MethodCaller GenGetMethod (PropertyInfo target) return null; } - Type[] parms = new Type[] { typeof (object), typeof (MessageReader), typeof (Message), typeof (MessageWriter) }; + var parms = new Type[] { + typeof (object), + typeof (MessageReader), + typeof (Message), + typeof (MessageWriter) + }; var method = new DynamicMethod ("PropertyGet", typeof(void), parms, typeof(MessageReader)); var ilg = method.GetILGenerator (); + var retLocal = ilg.DeclareLocal (mi.ReturnType); + ilg.Emit (OpCodes.Ldarg_0); ilg.EmitCall (mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi, null); - - LocalBuilder retLocal = ilg.DeclareLocal (mi.ReturnType); ilg.Emit (OpCodes.Stloc, retLocal); ilg.Emit (OpCodes.Ldarg_3); @@ -553,7 +570,7 @@ internal static MethodCaller GenGetMethod (PropertyInfo target) return (MethodCaller) method.CreateDelegate (typeof(MethodCaller)); } - internal static MethodCaller GenSetMethod (PropertyInfo target) + internal static MethodCaller GenSetCall (PropertyInfo target) { var mi = target.GetSetMethod (); @@ -561,7 +578,12 @@ internal static MethodCaller GenSetMethod (PropertyInfo target) return null; } - Type[] parms = new Type[] { typeof (object), typeof (MessageReader), typeof (Message), typeof (MessageWriter) }; + var parms = new Type[] { + typeof (object), + typeof (MessageReader), + typeof (Message), + typeof (MessageWriter) + }; var method = new DynamicMethod ("PropertySet", typeof(void), parms, typeof(MessageReader)); var ilg = method.GetILGenerator (); diff --git a/tests/ExportInterfaceTest.cs b/tests/ExportInterfaceTest.cs index b8891ea..bacb4b8 100644 --- a/tests/ExportInterfaceTest.cs +++ b/tests/ExportInterfaceTest.cs @@ -24,18 +24,18 @@ public class ExportInterfaceTest ObjectPath path = new ObjectPath ("/org/dbussharp/test"); int event_a_count = 0; - + [TestFixtureSetUp] - public void Setup () - { + public void Setup () + { test_server = new Test (); Bus.Session.Register (path, test_server); Assert.AreEqual (Bus.Session.RequestName (bus_name), RequestNameReply.PrimaryOwner); Assert.AreNotEqual (Bus.Session.RequestName (bus_name), RequestNameReply.PrimaryOwner); test = Bus.Session.GetObject (bus_name, path); - } - + } + /// /// ///