Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33efa9a4 authored by Sonny Sasaka's avatar Sonny Sasaka
Browse files

Improve D-Bus projection macros

Previously property maps need to be marked with attribute
dbus_propmap_field_enum and dbus_propmap_field_propmap since the macro
wasn't able to detect by itself. This patch improves the mechanism such
that the user does not have to declare the type but the macro can detect
by itself.

Bug: 186492781
Tag: #floss
Test: manual - build floss on Linux

Change-Id: Idf08d58824ac40e6bc6f02a1e6e3732674d8b12a
parent 564dde34
Loading
Loading
Loading
Loading
+68 −61
Original line number Diff line number Diff line
@@ -241,16 +241,6 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream {

        let field_str = field_ident.as_ref().unwrap().clone().to_string();

        let propmap_attr = field.attrs.clone().into_iter().find(|x| {
            let ident = x.path.get_ident();

            if ident.is_none() {
                return false;
            }

            ident.unwrap().to_string().eq("dbus_propmap_field_propmap")
        });

        let field_type_str = if let Type::Path(t) = field.ty {
            t.path.get_ident().unwrap().to_string()
        } else {
@@ -263,32 +253,7 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream {
            #field_idents #field_ident,
        };

        let make_field = if !propmap_attr.is_none() {
            quote! {
                let mut map: dbus::arg::PropMap = std::collections::HashMap::new();

                let mut iter = #field_ident.as_iter().unwrap();
                let mut iter = iter.next().unwrap().as_iter().unwrap();

                let mut i1 = iter.next();
                let mut i2 = iter.next();
                while !i1.is_none() && !i2.is_none() {
                    let k = i1.unwrap().as_str().unwrap().to_string();
                    let v = dbus::arg::Variant(i2.unwrap().box_clone());
                    map.insert(k, v);
                    i1 = iter.next();
                    i2 = iter.next();
                }

                let #field_ident = #field_type_ident::from_dbus(
                    map,
                    conn__.clone(),
                    remote__.clone(),
                    disconnect_watcher__.clone(),
                )?;
            }
        } else {
            quote! {
        let make_field = quote! {
            match #field_ident.arg_type() {
                dbus::arg::ArgType::Variant => {}
                _ => {
@@ -298,25 +263,16 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream {
                    )))));
                }
            };
                let #field_ident = #field_ident.as_static_inner(0).unwrap();
                let any = #field_ident.as_any();
                if !any.is::<<#field_type_ident as DBusArg>::DBusType>() {
                    return Err(Box::new(DBusArgError::new(String::from(format!(
                        "{}.{} type does not match: expected {}, found {}",
                        #struct_str,
                        #field_str,
                        std::any::type_name::<<#field_type_ident as DBusArg>::DBusType>(),
                        #field_ident.arg_type().as_str(),
                    )))));
                }
                let #field_ident = (*any.downcast_ref::<<#field_type_ident as DBusArg>::DBusType>().unwrap()).clone();
            let #field_ident = <<#field_type_ident as DBusArg>::DBusType as RefArgToRust>::ref_arg_to_rust(
                #field_ident,
                format!("{}.{}", #struct_str, #field_str),
            )?;
            let #field_ident = #field_type_ident::from_dbus(
                #field_ident,
                conn__.clone(),
                remote__.clone(),
                disconnect_watcher__.clone(),
            )?;
            }
        };

        make_fields = quote! {
@@ -556,6 +512,57 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream {

        impl Error for DBusArgError {}

        pub(crate) trait RefArgToRust {
            type RustType;
            fn ref_arg_to_rust<U: 'static + dbus::arg::RefArg + ?Sized>(
                arg: &U,
                name: String,
            ) -> Result<Self::RustType, Box<dyn Error>>;
        }

        impl<T: 'static + Clone + DirectDBus> RefArgToRust for T {
            type RustType = T;
            fn ref_arg_to_rust<U: 'static + dbus::arg::RefArg + ?Sized>(
                arg: &U,
                name: String,
            ) -> Result<Self::RustType, Box<dyn Error>> {
                let arg = arg.as_static_inner(0).unwrap();
                let any = arg.as_any();
                if !any.is::<<Self as DBusArg>::DBusType>() {
                    return Err(Box::new(DBusArgError::new(String::from(format!(
                        "{} type does not match: expected {}, found {}",
                        name,
                        std::any::type_name::<<Self as DBusArg>::DBusType>(),
                        arg.arg_type().as_str(),
                    )))));
                }
                let arg = (*any.downcast_ref::<<Self as DBusArg>::DBusType>().unwrap()).clone();
                return Ok(arg);
            }
        }

        impl RefArgToRust for dbus::arg::PropMap {
            type RustType = dbus::arg::PropMap;
            fn ref_arg_to_rust<U: 'static + dbus::arg::RefArg + ?Sized>(
                arg: &U,
                _name: String,
            ) -> Result<Self::RustType, Box<dyn Error>> {
                let mut map: dbus::arg::PropMap = std::collections::HashMap::new();
                let mut outer_iter = arg.as_iter().unwrap();
                let mut iter = outer_iter.next().unwrap().as_iter().unwrap();
                let mut key = iter.next();
                let mut val = iter.next();
                while !key.is_none() && !val.is_none() {
                    let k = key.unwrap().as_str().unwrap().to_string();
                    let v = dbus::arg::Variant(val.unwrap().box_clone());
                    map.insert(k, v);
                    key = iter.next();
                    val = iter.next();
                }
                return Ok(map);
            }
        }

        pub(crate) trait DBusArg {
            type DBusType;

+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ use std::error::Error;
use std::sync::Arc;
use std::sync::Mutex;

use crate::dbus_arg::{DBusArg, DBusArgError};
use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};

#[dbus_propmap(BluetoothDevice)]
pub struct BluetoothDeviceDBus {
+1 −6
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ use num_traits::cast::{FromPrimitive, ToPrimitive};
use std::error::Error;
use std::sync::{Arc, Mutex};

use crate::dbus_arg::{DBusArg, DBusArgError};
use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};

#[allow(dead_code)]
struct ScannerCallbackDBus {}
@@ -38,13 +38,8 @@ pub struct RSSISettingsDBus {
#[dbus_propmap(ScanSettings)]
struct ScanSettingsDBus {
    interval: i32,

    window: i32,

    #[dbus_propmap_field_enum]
    scan_type: ScanType,

    #[dbus_propmap_field_propmap]
    rssi_settings: RSSISettings,
}