Mercurial > projects > dbus-d
view dbus-d/dsrc/org/freedesktop/dbus/DBus.d @ 5:7c2c75740370
code generation for signals
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 21 Oct 2007 19:22:41 +0200 |
parents | a5576806d36d |
children | 963d271f7c25 |
line wrap: on
line source
/* * Copyright (C) 2007 Frank Benoit * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ module org.freedesktop.dbus.DBus; import tango.io.Stdout; import tango.core.Exception; import tango.core.Thread; import tango.core.Traits; import tango.text.convert.Integer; import tango.text.Util; public import tango.stdc.stringz : fromUtf8z; //public import tango.core.Tuple; //public import org.freedesktop.dbus.DBusInterface; import org.freedesktop.dbus.c.Connection; import org.freedesktop.dbus.c.Errors; import org.freedesktop.dbus.c.Message; import org.freedesktop.dbus.c.Bus; import org.freedesktop.dbus.c.PendingCall; import org.freedesktop.dbus.c.Shared; import org.freedesktop.dbus.c.Protocol; import org.freedesktop.dbus.c.Types; import org.freedesktop.dbus.c.Memory : dbus_free; import org.freedesktop.dbus.Struct; import org.freedesktop.dbus.Variant; //version=CD; typedef char[] DBusObjPath; typedef char[] DBusSignature; private void notImplemented( char[] msg = null ){ throw new TracedException( "not yet implemented " ~ msg ); } private void ensure( bool cond, char[][] msg ... ){ if( !cond ){ char[200] buf; char[] formattedMsg = layout( buf, msg ); throw new TracedException( "ensure failed: "~formattedMsg ); } } private void ensureDBus( dbus_bool_t cond ){ if( !cond ){ throw new TracedException( "ensureDBus" ); } } alias DBusHandlerResult function( DBusConnection* conn, DBusMessage* message, void* user_data ) DBusHandler; char[] [ ClassInfo ] registeredIntrospectionData; DBusHandler[ ClassInfo ] registeredHandlers; public void registerIntrospectionData( ClassInfo ci, char[] data ){ registeredIntrospectionData[ ci ] = data; } public void registerHandler( ClassInfo ci, DBusHandler handler ){ registeredHandlers[ ci ] = handler; } public class DBusObjectImpl { static uint sInstCounter = 0; char[] instName; this(){ //Stdout.formatln( "DBusObject ctor" ); int cnt; synchronized{ cnt = sInstCounter++; } instName = '/' ~ replace( this.classinfo.name.dup, '.', '/' ) ~ '/' ~ .toUtf8( cnt ); //Stdout.formatln( "DBusObject instname={}", instName ); } public char[] getDBusInstanceName(){ return instName; } public char[] Introspect(){ char[] res = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" "<node>\n"; bool[ ClassInfo ] all; void appendInterfaces( Interface[] intfs ){ foreach( intf; intfs ){ if( intf.classinfo.interfaces.length > 0 ){ appendInterfaces( intf.classinfo.interfaces ); } all[ intf.classinfo ] = true; } } appendInterfaces( this.classinfo.interfaces ); foreach( intf; all.keys ){ char[]* intro = intf in registeredIntrospectionData; if( intro !is null ){ res ~= *intro; } } DBusObjectImpl[] childs = getChildNodes(); foreach( child; childs ){ res ~= " <node name=\""~child.instName~"\"/>\n"; } res ~= "</node>\n"; //Stdout.formatln( "DBus.d:{} Introspect: {}", __LINE__, res ); return res; } public DBusObjectImpl[] getChildNodes(){ return null; } private static extern(C) DBusHandlerResult VTableMessageFunction( DBusConnection* conn, DBusMessage* message, void* user_data ) { char[METHOD_SIG_MAXLENGTH] buf; DBusObjectImpl o = cast(DBusObjectImpl)cast(Object)user_data; // find all interfaces ... bool[ ClassInfo ] all; void findAllInterfaces( Interface[] intfs ){ foreach( intf; intfs ){ findAllInterfaces( intf.classinfo.interfaces ); all[ intf.classinfo ] = true; } } ClassInfo oci = o.classinfo; do{ findAllInterfaces( oci.interfaces ); oci = oci.base; } while( oci !is null ); // call all existing handlers until message handled foreach( intf; all.keys ){ DBusHandler* handler = intf in registeredHandlers; if( handler !is null ){ DBusHandlerResult res = (*handler)( conn, message, user_data ); if( res == DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED ){ return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED; } } } return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } private static extern(C) void VTableUnregisterFunction( DBusConnection *connection, void* user_data ) { DBusObjectImpl o = cast(DBusObjectImpl)cast(Object)user_data; objectLocker.remove( o ); } private static DBusObjectPathVTable dbusObjectPathVTable = { message_function : & VTableMessageFunction, unregister_function : & VTableUnregisterFunction }; public void registerDBusObject( DBusConnection * conn ){ ensureDBus( dbus_connection_register_object_path( conn, XtoUtf8z( getDBusInstanceName() ), & dbusObjectPathVTable, cast(void*)cast(Object)this )); objectLocker[ this ] = true; } } bool[ DBusObjectImpl ] objectLocker; class DBusConnectionImpl { DBusConnection* conn; public this( char[] addr ){ DBusError err; int trial = 0; while( true ){ trial++; dbus_error_init(&err); scope(exit) if( dbus_error_is_set(&err) ){ dbus_error_free(&err); } conn = dbus_connection_open_private( XtoUtf8z(addr), & err ); if( !dbus_error_is_set(&err) && conn !is null ){ return; } if( trial > 10 ){ if( dbus_error_is_set(&err) ){ Stdout.formatln( "Connect Error ({})\n", fromUtf8z( err.message)); throw new Exception(""); } if( conn is null ){ throw new IOException("connecting not successful"); } } else{ Thread.sleep( 0.1 ); } } } /+ public DBusInterface getRemoteObject( char[] path ){ return null; }+/ public void mainLoop(){ //Stdout.formatln( " D mainloop starting" ); while (dbus_connection_read_write_dispatch (conn, -1)){ //Stdout.formatln( " D mainloop" ); // empty loop body } //Stdout.formatln( " D mainloop stop" ); return; DBusError err; dbus_error_init(&err); //CBus.dbus_bus_request_name(conn, XtoUtf8z("test.method.caller"), DBUS_NAME_FLAG_REPLACE_EXISTING , &err); if( dbus_error_is_set(&err) ){ Stdout.formatln( "Name Error ({})\n", fromUtf8z( err.message)); dbus_error_free(&err); throw new Exception(""); } } public void disconnect(){ if( conn !is null ){ dbus_connection_close( conn ); } } } class DirectConnection : DBusConnectionImpl { public this( char[] addr ){ super( addr ); } } class DBusExecutionException : TracedException { public this( char[] msg ){ super( msg ); } } template isDBusSimpleType(T){ const bool isDBusSimpleType = is( T == bool ) || is( T == byte ) || is( T == short ) || is( T == ushort ) || is( T == int ) || is( T == uint ) || is( T == long ) || is( T == ulong ) || is( T == double ); } private void getCallValue( T )( DBusMessageIter* iter, out T t ){ version(CD) pragma( msg, "getCallValue: "~T.stringof ); void testType( int type ){ int expected = dbus_message_iter_get_arg_type( iter ); ensure( expected == type, "getCallType(%0) type does not match %1 '%2' != %3 '%4'", T.stringof, toUtf8(type), [cast(char)type], toUtf8(expected), [cast(char)expected] ); } static if( false ){} else static if( isAssocArrayType!(T) ){ version(CD) pragma( msg, "getCallValue: assic "~typeof(T).stringof ); testType( DBUS_TYPE_ARRAY ); DBusMessageIter sub; dbus_message_iter_recurse( iter, &sub ); dbus_message_iter_next( iter ); typeof(T.keys [0]) key; typeof(T.values[0]) value; while( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){ ensure( dbus_message_iter_get_arg_type( &sub ) == DBUS_TYPE_DICT_ENTRY, "getCallType type does not match for Assoc" ); DBusMessageIter entry; dbus_message_iter_recurse( &sub, &entry ); dbus_message_iter_next( &sub ); getCallValue( &entry, key ); getCallValue( &entry, value ); t[ key ] = value; } } else static if( is( T == char[] )){ // char[] nicht als dyn array, sondern als String testType( DBUS_TYPE_STRING ); char* ptr; dbus_message_iter_get_basic( iter, & ptr ); dbus_message_iter_next( iter ); t = fromUtf8z( ptr ); } else static if( isDynamicArrayType!(T) ){ testType( DBUS_TYPE_ARRAY ); DBusMessageIter sub; dbus_message_iter_recurse( iter, &sub ); dbus_message_iter_next( iter ); static if( is( typeof(T[0]) == bool )) { version(CD) pragma( msg, "getCallValue: basic type "~typeof(T[0]).stringof ); if( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){ // special processing because of dbus bools are 4bytes vs. D bool is 1byte. dbus_bool_t* ptr; int n_elements; dbus_message_iter_get_fixed_array( & sub, &ptr, & n_elements ); t.length = n_elements; foreach( idx, v; ptr[ 0 .. n_elements ] ){ t[ idx ] = ( v != 0 ); } } } else static if( isDBusSimpleType!( typeof(T[0]) )) { version(CD) pragma( msg, "getCallValue: basic type "~typeof(T[0]).stringof ); if( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){ typeof(T[0])* ptr; int n_elements; dbus_message_iter_get_fixed_array( & sub, &ptr, & n_elements ); t = ptr[ 0 .. n_elements ].dup; } } else{ version(CD) pragma( msg, "getCallValue: composed type "~typeof(T[0]).stringof ); uint idx = 0; while( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){ t.length = t.length +1; getCallValue( &sub, t[idx] ); // dbus_message_iter_next( &sub ) : is done in getCallValue for element. idx++; } } } else static if( isDBusSimpleType!(T) ) { testType( DBusTypeIdFromDType!(T) ); dbus_message_iter_get_basic( iter, & t ); dbus_message_iter_next( iter ); } else static if( is( T : DBusObjectImpl )){ testType( DBusTypeIdFromDType!(T) ); static assert( false ); } else static if( is( T == DBusVariant ) ){ DBusMessageIter sub; dbus_message_iter_recurse( iter, &sub ); dbus_message_iter_next( iter ); char* sig = dbus_message_iter_get_signature( &sub ); scope(exit) dbus_free( sig ); char[] sigText = fromUtf8z( sig ); t = createDBusVariant( &sub, sigText ); } else static if( is( T == Struct!(typeof(T.t)) ) ){ // Stdout.formatln( "DBus getCallValue {}", __LINE__ ); DBusMessageIter sub; dbus_message_iter_recurse( iter, &sub ); dbus_message_iter_next( iter ); foreach( idx, el; t.t ){ getCallValue( & sub, t.t[idx] ); } } else{ pragma( msg, "getCallValue: "~typeof(t).stringof ); static assert(false, typeof(t).stringof ); } } public Struct!(T) getCallValues( T... )( DBusMessage* message ){ version(CD) pragma( msg, "getCallValues: "~T.stringof ); Struct!(T) res; DBusMessageIter args; dbus_message_iter_init( message, &args); foreach( idx, t; T ){ getCallValue( &args, res.t[idx] ); } return res; } private void _appendMsgParam( DBusMessageIter* iter, int type, void* ptr ){ if ( !dbus_message_iter_append_basic( iter, type, ptr ) ) { throw new TracedException( "Cannot append argument to iterator" ); } } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, bool value ){ dbus_bool_t val = value; _appendMsgParam( iter, DBUS_TYPE_BOOLEAN, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, byte value ){ dbus_bool_t val = value; _appendMsgParam( iter, DBUS_TYPE_BYTE, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, short value ){ dbus_int16_t val = value; _appendMsgParam( iter, DBUS_TYPE_INT16, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, ushort value ){ dbus_uint16_t val = value; _appendMsgParam( iter, DBUS_TYPE_UINT16, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, int value ){ dbus_int32_t val = value; _appendMsgParam( iter, DBUS_TYPE_INT32, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, uint value ){ dbus_int32_t val = value; _appendMsgParam( iter, DBUS_TYPE_UINT32, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, long value ){ dbus_int64_t val = value; _appendMsgParam( iter, DBUS_TYPE_INT64, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, ulong value ){ dbus_uint64_t val = value; _appendMsgParam( iter, DBUS_TYPE_UINT64, &val ); } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, double value ){ double val = value; _appendMsgParam( iter, DBUS_TYPE_DOUBLE, &val ); } private const char[] nullChar = "\0"; char* XtoUtf8z (char[] s) { if (s.length == 0) return nullChar.ptr; if (s[$-1] == '\0') return s.ptr; s ~= '\0'; return s.ptr; } void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, char[] value ){ //toUtf8z( value ); // toUtf8z return null for a null char[], but a valid ptr is needed. char* val = XtoUtf8z( value ); _appendMsgParam( iter, DBUS_TYPE_STRING, &val ); } void appendMsgParamObject( DBusConnection* conn, DBusMessageIter* iter, DBusObjectImpl value ){ value.registerDBusObject( conn ); char* path = XtoUtf8z( value.getDBusInstanceName()); _appendMsgParam( iter, DBUS_TYPE_OBJECT_PATH, &path ); } void appendMsgParamVariant( DBusConnection* conn, DBusMessageIter* iter, DBusVariant value ){ DBusMessageIter sub; ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_VARIANT, XtoUtf8z( value.getSig() ), &sub )); if( DBusVariantValueBool v = cast(DBusVariantValueBool)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueByte v = cast(DBusVariantValueByte)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueShort v = cast(DBusVariantValueShort)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueUShort v = cast(DBusVariantValueUShort)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueInt v = cast(DBusVariantValueInt)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueUInt v = cast(DBusVariantValueUInt)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueLong v = cast(DBusVariantValueLong)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueULong v = cast(DBusVariantValueULong)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueDouble v = cast(DBusVariantValueDouble)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantValueString v = cast(DBusVariantValueString)value ){ appendMsgParam( conn, &sub, v.value ); } else if( DBusVariantStruct v = cast(DBusVariantStruct)value ){ DBusMessageIter sub2; ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_STRUCT, XtoUtf8z( v.getSig() ), &sub2 )); foreach( el; v.values ){ appendMsgParamVariant( conn, &sub2, el ); } ensureDBus( dbus_message_iter_close_container( &sub, &sub2 )); } else if( DBusVariantArray v = cast(DBusVariantArray)value ){ DBusMessageIter sub2; ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_ARRAY, XtoUtf8z( v.getSig() ), &sub2 )); foreach( el; v.values ){ appendMsgParamVariant( conn, &sub2, el ); } ensureDBus( dbus_message_iter_close_container( &sub, &sub2 )); } else if( DBusVariantMap v = cast(DBusVariantMap)value ){ DBusMessageIter sub2; ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_ARRAY, XtoUtf8z( v.getSig() ), &sub2 )); foreach( entry; v.values ){ DBusMessageIter el; ensureDBus( dbus_message_iter_open_container( &sub2, DBUS_TYPE_DICT_ENTRY, null, &el )); appendMsgParamVariant( conn, &el, entry.key ); appendMsgParamVariant( conn, &el, entry.value ); ensureDBus( dbus_message_iter_close_container( &sub2, &el )); } ensureDBus( dbus_message_iter_close_container( &sub, &sub2 )); } else{ Stdout.formatln( "appendMsgParamVariant not handled case for sig: {}", value.getSig() ).flush(); ensure( false, "appendMsgParamVariant not handled case for sig: %0", value.getSig() ); } ensureDBus( dbus_message_iter_close_container( iter, &sub )); } void appendMsgParamArray( T )( DBusConnection* conn, DBusMessageIter* iter, T[] value ){ //pragma( msg, "appendMsgParamArray: "~typeof(T).stringof ); DBusMessageIter sub; //Stderr.formatln( "DBus {} {}", __LINE__,createDBusSignature!(T) ).flush; ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_ARRAY, XtoUtf8z( createDBusSignature!(T)), &sub )); foreach( item; value ){ appendItem!( typeof( item ))( conn, &sub, item ); } ensureDBus( dbus_message_iter_close_container( iter, &sub )); } void appendMsgParamStruct( T... )( DBusConnection* conn, DBusMessageIter* iter, T t ){ //pragma( msg, "appendMsgParamStruct: "~typeof(T).stringof ); DBusMessageIter sub; ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_STRUCT, XtoUtf8z( createDBusSignature!(T)), &sub )); foreach( item; t ){ appendItem( conn, &sub, item ); } ensureDBus( dbus_message_iter_close_container( iter, &sub )); } void appendMsgParamAssoc( K, V )( DBusConnection* conn, DBusMessageIter* iter, V[K] map ){ //pragma( msg, "appendMsgParamAssoc: key="~typeof(K).stringof~" value="~typeof(V).stringof ); DBusMessageIter sub; ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_ARRAY, XtoUtf8z( createDBusSignature!(V[K])[1..$] ), // "{ss}" this is without the leading 'a' for the array. &sub )); foreach( key, value; map ){ DBusMessageIter el; ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_DICT_ENTRY, null, &el )); appendItem!( K )( conn, &el, key ); appendItem!( V )( conn, &el, value ); ensureDBus( dbus_message_iter_close_container( &sub, &el )); } ensureDBus( dbus_message_iter_close_container( iter, &sub )); } template createDBusSignature(T...){ //pragma( msg, "createDBusSignature(T) : T="~typeof(T).stringof ); static if( T.length > 1 ){ //pragma( msg, "R.length>1" ); const char[] createDBusSignature = createDBusSignature!(T[0]) ~ createDBusSignature!(T[1..$]); } else static if( isAssocArrayType!(T[0]) ){ //pragma( msg, "createDBusSignature: key="~typeof(T.keys[0] ).stringof~" value="~typeof(T.values[0] ).stringof ); const char[] createDBusSignature = DBUS_TYPE_ARRAY_AS_STRING ~ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING ~ createDBusSignature!( typeof(T[0].keys[0] )) ~ createDBusSignature!( typeof(T[0].values[0] )) ~ DBUS_DICT_ENTRY_END_CHAR_AS_STRING; } else static if( isDynamicArrayType!(T[0]) ){ //pragma( msg, "createDBusSignature: arr="~typeof(T[0]).stringof ); static if( is( T[0] == char[] ) ){ const char[] createDBusSignature = DBUS_TYPE_STRING_AS_STRING; } else{ const char[] createDBusSignature = DBUS_TYPE_ARRAY_AS_STRING ~ createDBusSignature!(typeof(T[0][0])); } } else static if( is( T[0] == bool ) ){ const char[] createDBusSignature = DBUS_TYPE_BOOLEAN_AS_STRING; } else static if( is( T[0] == byte ) ){ const char[] createDBusSignature = DBUS_TYPE_BYTE_AS_STRING; } else static if( is( T[0] == short ) ){ const char[] createDBusSignature = DBUS_TYPE_INT16_AS_STRING; } else static if( is( T[0] == ushort ) ){ const char[] createDBusSignature = DBUS_TYPE_UINT16_AS_STRING; } else static if( is( T[0] == int ) ){ const char[] createDBusSignature = DBUS_TYPE_INT32_AS_STRING; } else static if( is( T[0] == uint ) ){ const char[] createDBusSignature = DBUS_TYPE_UINT32_AS_STRING; } else static if( is( T[0] == long ) ){ const char[] createDBusSignature = DBUS_TYPE_INT64_AS_STRING; } else static if( is( T[0] == ulong ) ){ const char[] createDBusSignature = DBUS_TYPE_UINT64_AS_STRING; } else static if( is( T[0] == double ) ){ const char[] createDBusSignature = DBUS_TYPE_DOUBLE_AS_STRING; } else static if( is( T[0] : DBusObjectImpl ) ){ const char[] createDBusSignature = DBUS_TYPE_OBJECT_PATH_AS_STRING; } else static if( is( T[0] == DBusVariant ) ){ const char[] createDBusSignature = DBUS_TYPE_VARIANT_AS_STRING; } else static if( is( T[0] == Struct!(typeof(T[0].t)) )){ //pragma( msg, "createDBusSignature Struct: t="~typeof(T[0].t).stringof ); const char[] createDBusSignature = DBUS_STRUCT_BEGIN_CHAR_AS_STRING ~ createDBusSignature!( typeof(T[0].t) ) ~ DBUS_STRUCT_END_CHAR_AS_STRING; } else { pragma( msg, "createDBusSignature(T) : T="~typeof(T).stringof ); static assert( false ); } } template DBusTypeIdFromDType(T){ //pragma( msg, "DBusTypeIdFromDType: "~typeof(T).stringof ); static if(false){} else static if( is( T == char[] ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_STRING; } else static if( isDynamicArrayType!(T) ){ const int DBusTypeIdFromDType = DBUS_TYPE_ARRAY; } else static if( is( T == bool ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_BOOLEAN; } else static if( is( T == byte ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_BYTE; } else static if( is( T == short ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_INT16; } else static if( is( T == ushort ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_UINT16; } else static if( is( T == int ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_INT32; } else static if( is( T == uint ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_UINT32; } else static if( is( T == long ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_INT64; } else static if( is( T == ulong ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_UINT64; } else static if( is( T == double ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_DOUBLE; } else static if( is( T : DBusObjectImpl ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_OBJECT_PATH; } else static if( is( T == DBusVariant ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_OBJECT_PATH; } else static if( is( T == Struct!(typeof(T.t)) ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_OBJECT_PATH; } else static assert(false); } void appendItem( T... )( DBusConnection* conn, DBusMessageIter * args, T t ){ //pragma( msg, ">>>appendItem input: "~typeof(t).stringof ); //Stderr.formatln( "DBus {} {}", __LINE__,T[0].stringof ).flush; static if( T.length > 1 ){ //pragma( msg, "T.length>1" ); appendItem(T[0])( conn, args, t[0] ); appendItem(T[1..$])( conn, args, t[1..$] ); } else static if( isAssocArrayType!(T[0]) ){ //pragma( msg, ">>> appendItem: assoc" ); //Stdout.formatln( "DBus {}", __LINE__ ); appendMsgParamAssoc( conn, args, t[0] ); } else static if( is( T[0] == char[] )){ // char[] nicht als dyn array, sondern als String //pragma( msg, ">>> appendItem: char[]" ); appendMsgParam( conn, args, t[0]); } else static if( isDynamicArrayType!(T[0]) ){ //pragma( msg, ">>> appendItem: []" ); //Stdout.formatln( "DBus {}", __LINE__ ); appendMsgParamArray( conn, args, t[0] ); } else static if( isDBusSimpleType!( T[0] ) ) { //pragma( msg, ">>> appendItem: integral" ); appendMsgParam( conn, args, t[0] ); } else static if( is( T[0] : DBusObjectImpl )){ //pragma( msg, ">>> appendItem: interface/class" ); appendMsgParamObject( conn, args, cast(DBusObjectImpl)t[0]); } else static if( is( T[0] == DBusVariant ) ){ appendMsgParamVariant( conn, args, t[0]); } else static if( is( T[0] == DBusObjPath ) ){ //pragma( msg, ">>> appendItem: path" ); Stdout.formatln( "DBus {}", __LINE__ ); notImplemented(); } else static if( is( T[0] == DBusSignature ) ){ //pragma( msg, ">>> appendItem: sig" ); Stdout.formatln( "DBus {}", __LINE__ ); notImplemented(); } else static if( is( T[0] == Struct!(typeof(T[0].t)) ) ){ //pragma( msg, ">>> appendItem: struct" ); appendMsgParamStruct( conn, args, t[0].t ); //pragma( msg, "struct: "~typeof(t).stringof ); } else{ pragma( msg, "appendItem: "~typeof(t).stringof ); static assert(false, typeof(t).stringof ); } } void sendReply( DBusConnection* conn, DBusMessage* message ){ Stdout.flush(); Stderr.flush(); DBusMessage* reply = dbus_message_new_method_return(message); scope(exit){ dbus_message_unref(reply); } dbus_bool_t res = dbus_connection_send(conn, reply, null ); dbus_connection_flush(conn); if( !res ){ throw new TracedException( "Cannot send. Out of memory." ); } } void sendReplyData( T... )( DBusConnection* conn, DBusMessage* message, Struct!(T) t ){ Stdout.flush(); Stderr.flush(); //Stdout.formatln( "DBus {}", __LINE__ ); DBusMessage* reply = dbus_message_new_method_return(message); scope(exit){ dbus_message_unref(reply); } //Stdout.formatln( "DBus {}", __LINE__ ); static if( t.t.length > 0 ){ DBusMessageIter args; dbus_message_iter_init_append( reply, &args); foreach( t_item; t.t ){ //Stdout.formatln( "DBus {}", __LINE__ ); //pragma( msg, "sendReply t: "~typeof(t).stringof ); //pragma( msg, "sendReply t_item: "~typeof(t_item).stringof ); appendItem( conn, & args, t_item ); //pragma( msg, "sendReply OK" ); } } //Stdout.formatln( "DBus {}", __LINE__ ); //Stdout.formatln( "reply sig : {}", fromUtf8z(dbus_message_get_signature(reply))); dbus_bool_t res = dbus_connection_send(conn, reply, null ); dbus_connection_flush(conn); if( !res ){ throw new TracedException( "Cannot send. Out of memory." ); } } void sendException( DBusConnection* conn, DBusMessage* message, Exception e ){ Stdout.flush(); Stderr.flush(); char* type; char[] msg = e.msg; if( IOException e2 = cast(IOException)e ){ type = XtoUtf8z(DBUS_ERROR_IO_ERROR); msg = "IOException " ~ msg; } else{ type = XtoUtf8z(DBUS_ERROR_FAILED); } if( TracedException te = cast(TracedException)e ){ foreach( m; te ){ msg ~= m ~ \n; } } DBusMessage* reply = dbus_message_new_error(message, type, XtoUtf8z("D Exception: " ~ msg) ); scope(exit){ dbus_message_unref(reply); } dbus_bool_t res = dbus_connection_send(conn, reply, null ); dbus_connection_flush(conn); if( !res ){ throw new TracedException( "Cannot send. Out of dbus-memory." ); } } bool checkIntf( char[] intfName, DBusMessage* message ){ char[] namedInterface = fromUtf8z( dbus_message_get_interface(message)); if( namedInterface.length == 0 ){ return true; // no interface named in call, so lets try } return namedInterface == intfName; } public const int METHOD_SIG_MAXLENGTH = 100; char[] methodSignature( DBusMessage* message, char[] buf = null ){ char[] name = fromUtf8z( dbus_message_get_member(message)); if( buf.length < name.length ){ buf.length = name.length; } buf[ 0 .. name.length ] = name; char[] sig = fromUtf8z( dbus_message_get_signature(message)); int sz = name.length+sig.length+1; if( buf.length < sz ){ buf.length= sz; } int type = dbus_message_get_type( message ); switch( type ){ case DBUS_MESSAGE_TYPE_METHOD_CALL: buf[name.length] = '|'; break; case DBUS_MESSAGE_TYPE_SIGNAL: buf[name.length] = '>'; break; case DBUS_MESSAGE_TYPE_METHOD_RETURN: case DBUS_MESSAGE_TYPE_ERROR: case DBUS_MESSAGE_TYPE_INVALID: default: ensure( false, "methodSignature for unknown type %0", toUtf8(type) ); } buf[name.length+1 .. sz ] = sig; return buf[0..sz]; } char[] nextSingleCompleteTypeSig( char[] sigText, inout int ate = 0 ){ if( sigText.length > ate || sigText.length == 0 ){ return null; } char[] sig = sigText[ ate .. $ ]; switch( sig[0] ){ case 'y': case 'b': case 'n': case 'q': case 'i': case 'u': case 'x': case 't': case 'd': case 's': case 'o': case 'g': case 'v': ate = 1; return sig[0..1]; default: ensure( sig.length > 1, "nextSingleCompleteTypeSig found %0 as a single type sig, which is unknown", sig[0..1] ); } if( sig[0] == 'a' ){ if( sig[ 1 ] == '{' ){ int idx = 2; nextSingleCompleteTypeSig( sig, idx ); nextSingleCompleteTypeSig( sig, idx ); ensure( sig.length > idx, "nextSingleCompleteTypeSig 2" ); ensure( sig[ idx ] == '}', "nextSingleCompleteTypeSig 3" ); idx++; ate += idx; return sig[ 0 .. idx ]; } else{ int idx = 1; nextSingleCompleteTypeSig( sig, idx ); ate += idx; return sig[ 0 .. idx ]; } } else if( sig[0] == '(' ){ int idx = 1; ensure( sig.length > idx, "nextSingleCompleteTypeSig 4" ); while( sig[ idx ] != ')' ){ nextSingleCompleteTypeSig( sig, idx ); ensure( sig.length > idx, "nextSingleCompleteTypeSig 5" ); } idx++; ate += idx; return sig[ 0 .. idx ]; } assert(false); } DBusVariant createDBusVariant( DBusMessageIter * iter, char[] sigText ){ if( sigText.length == 0 ){ return null; } void getBasic( void* ptr ){ dbus_message_iter_get_basic( iter, ptr ); dbus_message_iter_next( iter ); } switch( sigText[0] ){ case 'y': { DBusVariantValueByte res = new DBusVariantValueByte(); getBasic( & res.value ); return res; } case 'b': { DBusVariantValueBool res = new DBusVariantValueBool(); getBasic( & res.value ); return res; } case 'n': { DBusVariantValueShort res = new DBusVariantValueShort(); getBasic( & res.value ); return res; } case 'q': { DBusVariantValueUShort res = new DBusVariantValueUShort(); getBasic( & res.value ); return res; } case 'i': { DBusVariantValueInt res = new DBusVariantValueInt(); getBasic( & res.value ); return res; } case 'u': { DBusVariantValueUInt res = new DBusVariantValueUInt(); getBasic( & res.value ); return res; } case 'x': { DBusVariantValueLong res = new DBusVariantValueLong(); getBasic( & res.value ); return res; } case 't': { DBusVariantValueULong res = new DBusVariantValueULong(); getBasic( & res.value ); return res; } case 'd': { DBusVariantValueDouble res = new DBusVariantValueDouble(); getBasic( & res.value ); return res; } case 's': { DBusVariantValueString res = new DBusVariantValueString(); char* ptr; getBasic( & ptr ); res.value = fromUtf8z( ptr ); return res; } case 'v': { DBusVariantValueVariant res = new DBusVariantValueVariant(); DBusMessageIter subIter; dbus_message_iter_recurse( iter, &subIter ); dbus_message_iter_next( iter ); res.value = createDBusVariant( & subIter, sigText[1..$] ); return res; } case 'o': //"DBusObject" assert(false); case 'g': //"DBusSignature" assert(false); default: break; } if( sigText[0] == 'a' ){ if( sigText.length > 1 && sigText[ 1 ] == '{' ){ int idx = 2; char[] sigKey = nextSingleCompleteTypeSig( sigText, idx ); char[] sigValue = nextSingleCompleteTypeSig( sigText, idx ); DBusVariantMap res = new DBusVariantMap( sigKey, sigValue ); DBusMessageIter subIter; dbus_message_iter_recurse( iter, &subIter ); dbus_message_iter_next( iter ); while( dbus_message_iter_get_arg_type( &subIter ) != DBUS_TYPE_INVALID ){ ensure( dbus_message_iter_get_arg_type( &subIter ) == DBUS_TYPE_DICT_ENTRY, "createDBusVariant 1" ); DBusMessageIter entry; dbus_message_iter_recurse( &subIter, &entry ); dbus_message_iter_next( &subIter ); DBusVariantMapItem item; item.key = createDBusVariant( & subIter, sigKey ); item.value = createDBusVariant( & subIter, sigValue ); res.values ~= item; } return res; } else{ int idx = 1; char[] sigElement = nextSingleCompleteTypeSig( sigText, idx ); DBusVariantArray res = new DBusVariantArray( sigElement ); DBusMessageIter subIter; dbus_message_iter_recurse( iter, &subIter ); dbus_message_iter_next( iter ); while( dbus_message_iter_get_arg_type( &subIter ) != DBUS_TYPE_INVALID ){ DBusMessageIter entry; dbus_message_iter_recurse( &subIter, &entry ); dbus_message_iter_next( &subIter ); res.values ~= createDBusVariant( & subIter, sigElement ); } return res; } } else if( sigText[0] == '(' ){ DBusVariantStruct res = new DBusVariantStruct(); int idx = 1; ensure( sigText.length > idx, "createDBusVariant 2" ); DBusMessageIter subIter; dbus_message_iter_recurse( iter, &subIter ); dbus_message_iter_next( iter ); while( sigText[ idx ] != ')' ){ char[] sigElement = nextSingleCompleteTypeSig( sigText, idx ); ensure( sigText.length > idx, "createDBusVariant 3" ); res.values ~= createDBusVariant( & subIter, sigElement ); } return res; } assert(false); } T getVariantAsKnownType( T )( DBusVariant var ){ T res; static if( false ){} else static if( isAssocArrayType!(T) ){ version(CD) pragma( msg, "getVariantAsKnownType: assoc "~typeof(T).stringof ); DBusVariantMap map = cast(DBusVariantMap)var; ensure( map !is null, "getVariantAsKnownType map is null" ); typeof(T.keys [0]) k; typeof(T.values[0]) v; foreach( value; map.values ){ k = getVariantAsKnownType!( typeof(T.keys [0]) )( value.key ); v = getVariantAsKnownType!( typeof(T.values[0]) )( value.value ); res[ k ] = v; } } else static if( is( T == char[] )){ // char[] nicht als dyn array, sondern als String version(CD) pragma( msg, "getVariantAsKnownType: string "~typeof(T).stringof ); DBusVariantValueString str = cast(DBusVariantValueString)var; ensure( str !is null, "getVariantAsKnownType string is null" ); res = str.value; } else static if( isDynamicArrayType!(T) ){ version(CD) pragma( msg, "getVariantAsKnownType: [] "~typeof(T).stringof ); DBusVariantArray arr = cast(DBusVariantArray)var; ensure( arr !is null, "getVariantAsKnownType array is null" ); res = new typeof(T[0])[ arr.values.length ]; foreach( idx, value; arr.values ){ res[ idx ] = getVariantAsKnownType!( typeof(T[0]) )( value ); } } else static if( isDBusSimpleType!(T) ) { DBusVariantValue!(T) v = cast(DBusVariantValue!(T))var; ensure( v !is null, "getVariantAsKnownType value is null" ); res = v.value; } else static if( is( T : DBusObjectImpl )){ static assert( false ); } else static if( is( T == DBusVariant ) ){ res = var; } else static if( is( T == Struct!(typeof(T.t)) ) ){ DBusVariantStruct v = cast(DBusVariantStruct)var; ensure( v !is null, "getVariantAsKnownType isnull" ); foreach( idx, item; res.t ){ res.t[idx] = getVariantAsKnownType!( typeof(item) )( v.values[idx] ); } } else{ pragma( msg, "appendItem: "~typeof(t).stringof ); static assert(false, typeof(t).stringof ); } return res; } void testTemplateCompilation(){ getCallValues!( int[] )( null ); getCallValues!( int[ char[] ] )( null ); getCallValues!( DBusVariant[ DBusVariant ] )( null ); getCallValues!( Struct!( int[], long, char[], Struct!( bool ) ) )( null ); getVariantAsKnownType!( int[] )( null ); getVariantAsKnownType!( int[ char[] ] )( null ); getVariantAsKnownType!( DBusVariant[ DBusVariant ] )( null ); getVariantAsKnownType!( Struct!( int[], long, char[], Struct!( bool ) ) )( null ); } /** * this function shall be used like so: * --- * mixin( createJavaImplementation( "MyClass", ["I1", "I2" ] )); * --- * This creates a simple standard implementation by generating code in this form: * --- * class MyClass : I1, I2 { * mixin I1.JImpl!(); * mixin I2.JImpl!(); * } * --- * The given array with interfaces must not be zero length */ char[] createJavaImplementation( char[] className, char[][] interfaces ){ assert( interfaces.length > 0 ); char[] res = "class "~className~ " "; bool first = true; foreach( intf; interfaces ){ res ~= first ? ": " : ", "; first = false; res ~= intf; } res ~= " {\n"; foreach( intf; interfaces ){ res ~= " mixin "~intf~"._StdJavaImpl!();\n"; } res ~= "}\n"; return res; } char[] ctfeReplace( char[] text, char s, char r ){ char[] res; foreach( c; text ){ res ~= ( c == s ) ? r : c; } return res; } char[] createDImplementation( char[] className, char[][] interfaces ){ assert( interfaces.length > 0 ); char[] res = "abstract class "~className~ " : DBusObjectImpl "; foreach( intf; interfaces ){ res ~= ", "; res ~= intf; } res ~= " {\n"; foreach( intf; interfaces ){ res ~= " mixin "~intf~"._StdDImpl!() _StdDImpl_"~ctfeReplace( intf, '.', '_' )~";\n"; } res ~= " protected this(){\n"; foreach( intf; interfaces ){ res ~= " _StdDImpl_"~ ctfeReplace( intf, '.', '_' ) ~"._init();\n"; } res ~= " }\n"; res ~= "}\n"; return res; }