Skip to content

Commit

Permalink
Merge pull request #445 from Snarpix/add-user-types-in-generated-code
Browse files Browse the repository at this point in the history
Add annotation to specify user types in generated code
  • Loading branch information
diwic committed Jul 13, 2023
2 parents 1580702 + 81e099f commit 366a6dc
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 8 deletions.
2 changes: 2 additions & 0 deletions dbus-codegen-tests/Cargo.toml
Expand Up @@ -16,6 +16,8 @@ path = "src/lib.rs"
dbus = { path = "../dbus", version = "0.9", features=["futures"] }
dbus-tree = { path = "../dbus-tree", version = "0.9" }
dbus-crossroads = { path = "../dbus-crossroads" }
dbus-tokio = { path = "../dbus-tokio" }
tokio = {version = "1.0", features=["time", "net", "rt", "rt-multi-thread"]}

[build-dependencies]
dbus-codegen = { path = "../dbus-codegen" }
31 changes: 31 additions & 0 deletions dbus-codegen-tests/build.rs
Expand Up @@ -154,6 +154,33 @@ static DEPRECATED_XML: &'static str = r#"
</node>
"#;

static USER_TYPES_XML: &'static str = r#"
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="com.example.MyService1.InterestingInterface">
<method name="Method1">
<arg name="arg1" direction="in" type="s">
<annotation name="rs.dbus.ArgType" value="codegen_tests::user_type::MyType"/>
</arg>
<arg name="outarg2" direction="out" type="u">
<annotation name="rs.dbus.ArgType" value="codegen_tests::user_type::MyType"/>
</arg>
</method>
<signal name="Signal1">
<arg name="arg1" type="s">
<annotation name="rs.dbus.ArgType" value="codegen_tests::user_type::MyType"/>
</arg>
</signal>
<property name="Bar" type="y" access="readwrite">
<annotation name="rs.dbus.ArgType" value="codegen_tests::user_type::MyType"/>
</property>
</interface>
</node>
"#;

fn write_to_file(code: &str, path: &Path) {
let mut f = File::create(path).unwrap();
Write::write_all(&mut f,code.as_bytes()).unwrap();
Expand All @@ -179,13 +206,15 @@ fn main() {
..Default::default()
};
generate_code(POLICYKIT_XML, &blocking_client, "policykit_blocking.rs");
generate_code(USER_TYPES_XML, &blocking_client, "user_types_blocking.rs");

let nonblock_client = GenOpts {
connectiontype: ConnectionType::Nonblock,
methodtype: None,
..Default::default()
};
generate_code(POLICYKIT_XML, &nonblock_client, "policykit_nonblock.rs");
generate_code(USER_TYPES_XML, &nonblock_client, "user_types_nonblock.rs");

let mut g = GenOpts {
methodtype: Some("MTFnMut".into()),
Expand All @@ -202,10 +231,12 @@ fn main() {
g.methodtype = None;
g.propnewtype = true;
generate_code(POLICYKIT_XML, &g, "policykit_client.rs");
generate_code(USER_TYPES_XML, &g, "user_types_client.rs");

g.crossroads = true;
g.propnewtype = false;
g.skipprefix = Some("org.freedesktop".into());
generate_code(POLICYKIT_XML, &g, "policykit_cr.rs");
generate_code(DEPRECATED_XML, &g, "deprecated_cr.rs");
generate_code(USER_TYPES_XML, &g, "user_types_cr.rs");
}
1 change: 1 addition & 0 deletions dbus-codegen-tests/src/lib.rs
@@ -0,0 +1 @@
pub mod user_type;
74 changes: 74 additions & 0 deletions dbus-codegen-tests/src/user_type.rs
@@ -0,0 +1,74 @@
use dbus::arg::{Append, IterAppend, Iter, Arg, ArgType, Get, RefArg};
use dbus::strings::Signature;
use std::any;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MyType
{
f: (String, String),
}

impl MyType {
pub fn new(s1: String, s2: String) -> Self {
MyType{f:(s1, s2)}
}
}

impl Append for MyType {
fn append_by_ref(&self, i: &mut IterAppend) {
self.f.append_by_ref(i);
}
}

impl Arg for MyType {
const ARG_TYPE: ArgType = ArgType::Struct;
fn signature() -> Signature<'static> {
Signature::new("(ss)".to_string()).unwrap()
}
}

impl<'a> Get<'a> for MyType {
fn get(i: &mut Iter<'a>) -> Option<MyType> {
let f = <(String, String)>::get(i)?;
Some(MyType{f})
}
}

impl RefArg for MyType {
fn arg_type(&self) -> ArgType {
<MyType as Arg>::ARG_TYPE
}
fn signature(&self) -> Signature<'static> {
<MyType as Arg>::signature()
}
fn append(&self, i: &mut IterAppend) {
<MyType as Append>::append_by_ref(self, i)
}
fn as_any(&self) -> &dyn any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn any::Any {
self
}
fn as_i64(&self) -> Option<i64> {
None
}
fn as_u64(&self) -> Option<u64> {
None
}
fn as_f64(&self) -> Option<f64> {
None
}
fn as_str(&self) -> Option<&str> {
None
}
fn box_clone(&self) -> Box<dyn RefArg + 'static> {
Box::new(self.clone())
}
fn array_clone(v: &[Self]) -> Option<Box<dyn RefArg + 'static>>
where
Self: Sized,
{
Some(Box::new(v.to_vec()))
}
}
81 changes: 81 additions & 0 deletions dbus-codegen-tests/tests/test_user_types.rs
@@ -0,0 +1,81 @@
mod user_types_dbus;

use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use dbus::blocking::Connection;
use dbus::channel::MatchingReceiver;
use dbus_crossroads::Crossroads;

use codegen_tests::user_type::MyType;
use user_types_dbus::*;

struct MyServer {
t: MyType,
}

impl MyServer {
fn new() -> Self {
MyServer{t: MyType::new("123".to_string(), "456".to_string())}
}
}

impl user_types_cr::ComExampleMyService1InterestingInterface for MyServer {
fn method1(&mut self, arg1: codegen_tests::user_type::MyType) -> Result<codegen_tests::user_type::MyType, dbus::MethodErr>{
return Ok(arg1);
}
fn bar(&self) -> Result<codegen_tests::user_type::MyType, dbus::MethodErr> {
return Ok(self.t.clone());
}
fn set_bar(&self, _value: codegen_tests::user_type::MyType) -> Result<(), dbus::MethodErr> {
return Ok(());
}
}


#[test]
fn test_cr() {
let c = Connection::new_session().unwrap();
let cname = "com.example.dbustest";
c.request_name(cname, false, true, false).unwrap();
let mut cr = Crossroads::new();
let token = user_types_cr::register_com_example_my_service1_interesting_interface::<MyServer>(&mut cr);
let server = MyServer::new();
cr.insert("/", &[token], server);
c.start_receive(dbus::message::MatchRule::new_method_call(), Box::new(move |msg, conn| {
cr.handle_message(msg, conn).unwrap();
true
}));

let quit = std::sync::Arc::new(AtomicBool::new(false));
let quit2 = quit.clone();

let _ = std::thread::spawn(move || {
{
let c2 = dbus::blocking::Connection::new_session().unwrap();
let p = c2.with_proxy(cname, "/", std::time::Duration::from_millis(1000));
use user_types_blocking::ComExampleMyService1InterestingInterface;
let arg = MyType::new("abc".to_string(), "cdf".to_string());
assert_eq!(p.method1(&arg).unwrap(), arg);
}

let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let (resource, conn) = dbus_tokio::connection::new_session_sync().unwrap();
let _handle = tokio::spawn(async {
let err = resource.await;
panic!("Lost connection to D-Bus: {}", err);
});
let p = dbus::nonblock::Proxy::new(cname, "/", Duration::from_secs(2), conn);
use user_types_nonblock::ComExampleMyService1InterestingInterface;
let arg = MyType::new("abc".to_string(), "cdf".to_string());
assert_eq!(p.method1(&arg).await.unwrap(), arg);
});

quit2.store(true, Ordering::SeqCst);
});

loop {
c.process(std::time::Duration::from_millis(1000)).unwrap();
if quit.load(Ordering::SeqCst) { break; }
}
}
4 changes: 4 additions & 0 deletions dbus-codegen-tests/tests/user_types_dbus/mod.rs
@@ -0,0 +1,4 @@
pub mod user_types_blocking;
pub mod user_types_client;
pub mod user_types_cr;
pub mod user_types_nonblock;
@@ -0,0 +1,3 @@
#![allow(dead_code)]
#![deny(trivial_casts)]
include!(concat!(env!("OUT_DIR"), "/user_types_blocking.rs"));
3 changes: 3 additions & 0 deletions dbus-codegen-tests/tests/user_types_dbus/user_types_client.rs
@@ -0,0 +1,3 @@
#![allow(dead_code)]
#![deny(trivial_casts)]
include!(concat!(env!("OUT_DIR"), "/user_types_client.rs"));
3 changes: 3 additions & 0 deletions dbus-codegen-tests/tests/user_types_dbus/user_types_cr.rs
@@ -0,0 +1,3 @@
#![allow(dead_code)]
#![deny(trivial_casts)]
include!(concat!(env!("OUT_DIR"), "/user_types_cr.rs"));
@@ -0,0 +1,3 @@
#![allow(dead_code)]
#![deny(trivial_casts)]
include!(concat!(env!("OUT_DIR"), "/user_types_nonblock.rs"));
18 changes: 13 additions & 5 deletions dbus-codegen/src/generate.rs
Expand Up @@ -82,6 +82,7 @@ pub fn generate(xmldata: &str, opts: &GenOpts) -> Result<String, Box<dyn error::
let mut curm = None;
let mut cursig = None;
let mut curprop = None;
let mut curarg = None;
let parser = EventReader::new(io::Cursor::new(xmldata));
for e in parser {
match e? {
Expand Down Expand Up @@ -182,17 +183,24 @@ pub fn generate(xmldata: &str, opts: &GenOpts) -> Result<String, Box<dyn error::
_ => { Err("Invalid direction")?; unreachable!() }
};
let no_refs = is_out || cursig.is_some() || opts.crossroads;
curarg = Some(Arg { name: find_attr(attributes, "name").unwrap_or("").into(),
typ: typ, no_refs, idx: 0, is_out, annotations: HashMap::new() });
}

XmlEvent::EndElement { ref name } if &name.local_name == "arg" => {
if curarg.is_none() { Err("End of arg outside arg")? };
let arg = curarg.as_mut().unwrap();
let arr = if let Some(ref mut sig) = cursig { &mut sig.args }
else if is_out { &mut curm.as_mut().unwrap().oargs } else { &mut curm.as_mut().unwrap().iargs };
let arg = Arg { name: find_attr(attributes, "name").unwrap_or("").into(),
typ: typ, no_refs, idx: arr.len() as i32 };
arr.push(arg);
else if arg.is_out { &mut curm.as_mut().unwrap().oargs } else { &mut curm.as_mut().unwrap().iargs };
arg.idx = arr.len() as i32;
arr.push(curarg.take().unwrap());
}

XmlEvent::StartElement { ref name, ref attributes, ..} if &name.local_name == "annotation" => {
if let Ok(key) = find_attr(attributes, "name") {
if let Ok(value) = find_attr(attributes, "value") {
if let Some(ref mut sig) = cursig { sig.annotations.insert(key.into(), value.into()); }
if let Some(ref mut arg) = curarg { arg.annotations.insert(key.into(), value.into()); }
else if let Some(ref mut sig) = cursig { sig.annotations.insert(key.into(), value.into()); }
else if let Some(ref mut prop) = curprop { prop.annotations.insert(key.into(), value.into()); }
else if let Some(ref mut met) = curm { met.annotations.insert(key.into(), value.into()); }
else if let Some(ref mut intf) = curintf { intf.annotations.insert(key.into(), value.into()); }
Expand Down
28 changes: 28 additions & 0 deletions dbus-codegen/src/generate/types.rs
Expand Up @@ -6,6 +6,8 @@ pub (super) struct Arg {
pub typ: String,
pub idx: i32,
pub no_refs: bool,
pub is_out: bool,
pub annotations: HashMap<String, String>,
}

pub (super) struct Method {
Expand Down Expand Up @@ -243,6 +245,9 @@ impl Arg {
} else { self.varname() }
}
pub fn typename(&self, genvar: bool) -> Result<(String, Vec<String>), Box<dyn error::Error>> {
if let Some(u) = self.user_type() {
return Ok((u, vec!()));
}
let mut g = if genvar { Some(GenVars {
prefix: format!("{}{}", if self.no_refs { 'R' } else { 'I' }, self.idx),
gen: vec!(),
Expand All @@ -253,6 +258,9 @@ impl Arg {
).collect()).unwrap_or(vec!())))
}
pub fn typename_norefs(&self) -> Result<String, Box<dyn error::Error>> {
if let Some(u) = self.user_type() {
return Ok(u);
}
make_type(&self.typ, true, &mut None)
}
pub fn typename_maybewrap(&self, genvar: bool) -> Result<String, Box<dyn error::Error>> {
Expand All @@ -261,9 +269,29 @@ impl Arg {
format!("arg::Variant<{}>", t)
} else { t })
}
fn user_type(&self) -> Option<String> {
if let Some(v) = self.annotations.get("rs.dbus.ArgType") {
let mut t = if self.no_refs {
"".to_owned()
} else {
"&".to_owned()
};
t += v;
Some(t)
} else {
None
}
}
}

impl Prop {
pub fn can_get(&self) -> bool { self.access != "write" }
pub fn can_set(&self) -> bool { self.access == "write" || self.access == "readwrite" }
pub fn typename(&self) -> Result<String, Box<dyn error::Error>> {
if let Some(v) = self.annotations.get("rs.dbus.ArgType") {
Ok(v.clone())
} else {
make_type(&self.typ, true, &mut None)
}
}
}
6 changes: 3 additions & 3 deletions dbus-codegen/src/generate/write.rs
Expand Up @@ -85,10 +85,10 @@ fn write_prop_signature(s: &mut String, p: &Prop, opts: &GenOpts, context: GenCo
}
if set {
*s += &format!(" fn {}(&self, value: {}) -> {}",
p.set_fn_name, make_type(&p.typ, true, &mut None)?, make_result("()", opts));
p.set_fn_name, p.typename()?, make_result("()", opts));
} else {
*s += &format!(" fn {}(&self) -> {}",
p.get_fn_name, make_result(&make_type(&p.typ, true, &mut None)?, opts));
p.get_fn_name, make_result(&p.typename()?, opts));
};
Ok(())
}
Expand Down Expand Up @@ -336,7 +336,7 @@ where T: {} + Send + 'static
*s += &format!(" }}){};\n", cr_anno(&m.annotations, " ", ""));
}
for p in &i.props {
*s += &format!(" b.property::<{}, _>(\"{}\")", make_type(&p.typ, true, &mut None)?, p.name);
*s += &format!(" b.property::<{}, _>(\"{}\")", p.typename()?, p.name);
if p.can_get() {
*s += &format!("\n .get(|_, t| t.{}())", p.get_fn_name);
}
Expand Down

0 comments on commit 366a6dc

Please sign in to comment.