[vala] D-Bus: Support struct return values in static clients and servers



commit fb437864b4fa314c28e8d1a6135588de8283ca62
Author: Jürg Billeter <j bitron ch>
Date:   Sat Dec 19 15:02:02 2009 +0100

    D-Bus: Support struct return values in static clients and servers

 codegen/valadbusclientmodule.vala |  133 +++++++++++++++++++++++--------------
 codegen/valadbusservermodule.vala |   74 +++++++++++++-------
 tests/Makefile.am                 |    1 +
 tests/dbus/structs.test           |   93 ++++++++++++++++++++++++++
 4 files changed, 225 insertions(+), 76 deletions(-)
---
diff --git a/codegen/valadbusclientmodule.vala b/codegen/valadbusclientmodule.vala
index bcddb07..2b6d965 100644
--- a/codegen/valadbusclientmodule.vala
+++ b/codegen/valadbusclientmodule.vala
@@ -1475,28 +1475,34 @@ internal class Vala.DBusClientModule : DBusModule {
 		}
 
 		if (!(m.return_type is VoidType)) {
-			cdecl = new CCodeDeclaration (m.return_type.get_cname ());
-			cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
-			postfragment.append (cdecl);
+			if (m.return_type.is_real_struct_type ()) {
+				var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
+				var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target);
+				postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+			} else {
+				cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
+				postfragment.append (cdecl);
 
-			var array_type = m.return_type as ArrayType;
+				var array_type = m.return_type as ArrayType;
 
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					cdecl = new CCodeDeclaration ("int");
-					cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
-					postfragment.append (cdecl);
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
+						postfragment.append (cdecl);
+					}
 				}
-			}
 
-			var target = new CCodeIdentifier ("_result");
-			var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target);
-			postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+				var target = new CCodeIdentifier ("_result");
+				var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target);
+				postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
 
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					// TODO check that parameter is not NULL (out parameters are optional)
-					postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						// TODO check that parameter is not NULL (out parameters are optional)
+						postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
+					}
 				}
 			}
 		}
@@ -1571,7 +1577,7 @@ internal class Vala.DBusClientModule : DBusModule {
 			set_error_call.add_argument (new CCodeConstant ("\"Connection is closed\""));
 			dispose_return_block.add_statement (new CCodeExpressionStatement (set_error_call));
 		}
-		if (m.return_type is VoidType) {
+		if (m.return_type is VoidType || m.return_type.is_real_struct_type ()) {
 			dispose_return_block.add_statement (new CCodeReturnStatement ());
 		} else {
 			dispose_return_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
@@ -1639,7 +1645,7 @@ internal class Vala.DBusClientModule : DBusModule {
 		reply_unref.add_argument (new CCodeIdentifier ("_reply"));
 		block.add_statement (new CCodeExpressionStatement (reply_unref));
 
-		if (!(m.return_type is VoidType)) {
+		if (!(m.return_type is VoidType || m.return_type.is_real_struct_type ())) {
 			block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
 		}
 
@@ -2002,20 +2008,28 @@ internal class Vala.DBusClientModule : DBusModule {
 
 		function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
 
-		if (array_type != null) {
-			for (int dim = 1; dim <= array_type.rank; dim++) {
-				function.add_parameter (new CCodeFormalParameter ("result_length%d".printf (dim), "int*"));
+		if (prop.property_type.is_real_struct_type ()) {
+			function.add_parameter (new CCodeFormalParameter ("result", "%s*".printf (prop.set_accessor.value_type.get_cname ())));
+		} else {
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					function.add_parameter (new CCodeFormalParameter ("result_length%d".printf (dim), "int*"));
+				}
 			}
-		}
 
-		function.return_type = prop.get_accessor.value_type.get_cname ();
+			function.return_type = prop.get_accessor.value_type.get_cname ();
+		}
 
 		var block = new CCodeBlock ();
 		var prefragment = new CCodeFragment ();
 		var postfragment = new CCodeFragment ();
 
 		var dispose_return_block = new CCodeBlock ();
-		dispose_return_block.add_statement (new CCodeReturnStatement (default_value_for_type (prop.property_type, false)));
+		if (prop.property_type.is_real_struct_type ()) {
+			dispose_return_block.add_statement (new CCodeReturnStatement ());
+		} else {
+			dispose_return_block.add_statement (new CCodeReturnStatement (default_value_for_type (prop.property_type, false)));
+		}
 		block.add_statement (new CCodeIfStatement (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), iface.get_cname () + "DBusProxy*"), "disposed"), dispose_return_block));
 
 		cdecl = new CCodeDeclaration ("DBusGConnection");
@@ -2061,31 +2075,37 @@ internal class Vala.DBusClientModule : DBusModule {
 		// property name
 		write_expression (prefragment, string_type, new CCodeIdentifier ("_iter"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
 
-		cdecl = new CCodeDeclaration (prop.get_accessor.value_type.get_cname ());
-		cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
-		postfragment.append (cdecl);
-
-		if (array_type != null) {
-			for (int dim = 1; dim <= array_type.rank; dim++) {
-				cdecl = new CCodeDeclaration ("int");
-				cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
-				postfragment.append (cdecl);
-			}
-		}
-
 		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
 		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
 		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_subiter")));
 		postfragment.append (new CCodeExpressionStatement (iter_call));
 
-		var target = new CCodeIdentifier ("_result");
-		var expr = read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_subiter"), target);
-		postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+		if (prop.property_type.is_real_struct_type ()) {
+			var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
+			var expr = read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_subiter"), target);
+			postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+		} else {
+			cdecl = new CCodeDeclaration (prop.get_accessor.value_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
+			postfragment.append (cdecl);
+
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					cdecl = new CCodeDeclaration ("int");
+					cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
+					postfragment.append (cdecl);
+				}
+			}
 
-		if (array_type != null) {
-			for (int dim = 1; dim <= array_type.rank; dim++) {
-				// TODO check that parameter is not NULL (out parameters are optional)
-				postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
+			var target = new CCodeIdentifier ("_result");
+			var expr = read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_subiter"), target);
+			postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					// TODO check that parameter is not NULL (out parameters are optional)
+					postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
+				}
 			}
 		}
 
@@ -2120,7 +2140,11 @@ internal class Vala.DBusClientModule : DBusModule {
 		reply_unref.add_argument (new CCodeIdentifier ("_reply"));
 		block.add_statement (new CCodeExpressionStatement (reply_unref));
 
-		block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
+		if (prop.property_type.is_real_struct_type ()) {
+			block.add_statement (new CCodeReturnStatement ());
+		} else {
+			block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
+		}
 
 		source_declarations.add_type_member_declaration (function.copy ());
 		function.block = block;
@@ -2142,11 +2166,16 @@ internal class Vala.DBusClientModule : DBusModule {
 		function.modifiers = CCodeModifiers.STATIC;
 
 		function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
-		function.add_parameter (new CCodeFormalParameter ("value", prop.set_accessor.value_type.get_cname ()));
 
-		if (array_type != null) {
-			for (int dim = 1; dim <= array_type.rank; dim++) {
-				function.add_parameter (new CCodeFormalParameter ("value_length%d".printf (dim), "int"));
+		if (prop.property_type.is_real_struct_type ()) {
+			function.add_parameter (new CCodeFormalParameter ("value", "%s*".printf (prop.set_accessor.value_type.get_cname ())));
+		} else {
+			function.add_parameter (new CCodeFormalParameter ("value", prop.set_accessor.value_type.get_cname ()));
+
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					function.add_parameter (new CCodeFormalParameter ("value_length%d".printf (dim), "int"));
+				}
 			}
 		}
 
@@ -2209,7 +2238,11 @@ internal class Vala.DBusClientModule : DBusModule {
 		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_subiter")));
 		prefragment.append (new CCodeExpressionStatement (iter_call));
 
-		write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_subiter"), new CCodeIdentifier ("value"));
+		if (prop.property_type.is_real_struct_type ()) {
+			write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_subiter"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")));
+		} else {
+			write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_subiter"), new CCodeIdentifier ("value"));
+		}
 
 		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
 		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
diff --git a/codegen/valadbusservermodule.vala b/codegen/valadbusservermodule.vala
index 13f895d..cfed028 100644
--- a/codegen/valadbusservermodule.vala
+++ b/codegen/valadbusservermodule.vala
@@ -785,18 +785,26 @@ internal class Vala.DBusServerModule : DBusClientModule {
 			cdecl = new CCodeDeclaration (prop.property_type.get_cname ());
 			cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
 			postfragment.append (cdecl);
-			postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
 
-			var array_type = prop.property_type as ArrayType;
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					string length_cname = get_array_length_cname ("result", dim);
+			if (prop.property_type.is_real_struct_type ()) {
+				// structs are returned via out parameter
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
 
-					cdecl = new CCodeDeclaration ("int");
-					cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
-					postfragment.append (cdecl);
+				postfragment.append (new CCodeExpressionStatement (ccall));
+			} else {
+				postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
+
+				var array_type = prop.property_type as ArrayType;
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						string length_cname = get_array_length_cname ("result", dim);
+
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
+						postfragment.append (cdecl);
 
-					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+					}
 				}
 			}
 
@@ -993,18 +1001,26 @@ internal class Vala.DBusServerModule : DBusClientModule {
 			cdecl = new CCodeDeclaration (prop.property_type.get_cname ());
 			cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
 			postfragment.append (cdecl);
-			postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
 
-			var array_type = prop.property_type as ArrayType;
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					string length_cname = get_array_length_cname ("result", dim);
+			if (prop.property_type.is_real_struct_type ()) {
+				// structs are returned via out parameter
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
 
-					cdecl = new CCodeDeclaration ("int");
-					cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
-					postfragment.append (cdecl);
+				postfragment.append (new CCodeExpressionStatement (ccall));
+			} else {
+				postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
 
-					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+				var array_type = prop.property_type as ArrayType;
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						string length_cname = get_array_length_cname ("result", dim);
+
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
+						postfragment.append (cdecl);
+
+						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+					}
 				}
 			}
 
@@ -1168,16 +1184,22 @@ internal class Vala.DBusServerModule : DBusClientModule {
 
 			var ccall = new CCodeFunctionCall (new CCodeIdentifier (prop.set_accessor.get_cname ()));
 			ccall.add_argument (new CCodeIdentifier ("self"));
-			ccall.add_argument (new CCodeIdentifier ("value"));
 
-			var array_type = prop.property_type as ArrayType;
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					cdecl = new CCodeDeclaration ("int");
-					cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname ("value", dim)));
-					prefragment.append (cdecl);
+			if (prop.property_type.is_real_struct_type ()) {
+				// structs are passed by reference
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
+			} else {
+				ccall.add_argument (new CCodeIdentifier ("value"));
+
+				var array_type = prop.property_type as ArrayType;
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname ("value", dim)));
+						prefragment.append (cdecl);
 
-					ccall.add_argument (new CCodeIdentifier (head.get_array_length_cname ("value", dim)));
+						ccall.add_argument (new CCodeIdentifier (head.get_array_length_cname ("value", dim)));
+					}
 				}
 			}
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 87d3b72..09d0640 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -74,6 +74,7 @@ TESTS = \
 	asynchronous/bug601558.vala \
 	dbus/basic-types.test \
 	dbus/arrays.test \
+	dbus/structs.test \
 	dbus/async.test \
 	dbus/bug596862.vala \
 	$(NULL)
diff --git a/tests/dbus/structs.test b/tests/dbus/structs.test
new file mode 100644
index 0000000..744aad4
--- /dev/null
+++ b/tests/dbus/structs.test
@@ -0,0 +1,93 @@
+Packages: dbus-glib-1
+
+Program: client
+
+struct FooStruct {
+	int i;
+	string s;
+
+	public FooStruct (int i, string s) {
+		this.i = i;
+		this.s = s;
+	}
+}
+
+[DBus (name = "org.example.Test")]
+interface Test : Object {
+	public abstract FooStruct test_property { owned get; set; }
+
+	public abstract FooStruct test_struct (FooStruct f, out FooStruct g) throws DBus.Error;
+}
+
+void main () {
+	var conn = DBus.Bus.get (DBus.BusType.SESSION);
+
+	// client
+	var test = (Test) conn.get_object ("org.example.Test", "/org/example/test");
+
+	FooStruct f, g, h;
+	f = FooStruct (42, "hello");
+	h = test.test_struct (f, out g);
+	assert (g.i == 23);
+	assert (g.s == "world");
+	assert (h.i == 11);
+	assert (h.s == "vala");
+
+	test.test_property = f;
+	g = test.test_property;
+	assert (g.i == 42);
+	assert (g.s == "hello");
+}
+
+Program: server
+
+struct FooStruct {
+	int i;
+	string s;
+
+	public FooStruct (int i, string s) {
+		this.i = i;
+		this.s = s;
+	}
+}
+
+[DBus (name = "org.example.Test")]
+class Test : Object {
+	public FooStruct test_property { owned get; set; }
+
+	public FooStruct test_struct (FooStruct f, out FooStruct g) {
+		assert (f.i == 42);
+		assert (f.s == "hello");
+		g = FooStruct (23, "world");
+		return FooStruct (11, "vala");
+	}
+}
+
+MainLoop main_loop;
+
+void client_exit (Pid pid, int status) {
+	// client finished, terminate server
+	assert (status == 0);
+	main_loop.quit ();
+}
+
+void main () {
+	var conn = DBus.Bus.get (DBus.BusType.SESSION);
+	dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus");
+
+	// try to register service in session bus
+	uint request_name_result = bus.request_name ("org.example.Test", (uint) 0);
+	assert (request_name_result == DBus.RequestNameReply.PRIMARY_OWNER);
+
+	// start server
+	var server = new Test ();
+	conn.register_object ("/org/example/test", server);
+
+	// server ready, spawn client
+	Pid client_pid;
+	Process.spawn_async (null, { "test", "/dbus/structs/client" }, null, SpawnFlags.DO_NOT_REAP_CHILD, null, out client_pid);
+	ChildWatch.add (client_pid, client_exit);
+
+	main_loop = new MainLoop (null, false);
+	main_loop.run ();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]