Skip to content

Commit

Permalink
Create a unified macro to derive all the encodable traits
Browse files Browse the repository at this point in the history
The derives are getting very verbose, which is especially bad for users
that want to create their own custom structs. This adds an attribute macro that
simply derives these traits as appropriate.

I also found an issue with the XML parsing and custom codegen that
required an unpleasant workaround.
  • Loading branch information
einarmo committed Feb 28, 2025
1 parent 4923abd commit 815a87b
Show file tree
Hide file tree
Showing 321 changed files with 830 additions and 5,760 deletions.
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Mark generated files as generated, for github
Cargo.lock linguist-generated=true
async-opcua-types/src/generated/** linguist-generated=true
async-opcua-core-namespace/src/generated/** linguist-generated=true
async-opcua-core-namespace/src/events/generated.rs linguist-generated=true
8 changes: 1 addition & 7 deletions async-opcua-codegen/src/nodeset/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,7 @@ impl<'a> ValueBuilder<'a> {
});
};

let element = XmlElement::parse(data)?;
let Some(element) = element else {
return Ok(quote::quote! {
opcua::types::ExtensionObject::null()
});
};
let content = self.render_extension_object_inner(&element)?;
let content = self.render_extension_object_inner(data)?;

Ok(quote! {
opcua::types::ExtensionObject::from_message(#content)
Expand Down
33 changes: 8 additions & 25 deletions async-opcua-codegen/src/types/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,27 +445,16 @@ impl CodeGenerator {
let mut attrs = Vec::new();
let mut variants = Punctuated::new();

attrs.push(parse_quote! {
#[opcua::types::ua_encodable]
});
if let Some(doc) = item.documentation {
attrs.push(parse_quote! {
#[doc = #doc]
});
}
attrs.push(parse_quote! {
#[derive(Debug, Copy, Clone, PartialEq, Eq,
opcua::types::UaEnum, opcua::types::BinaryEncodable,
opcua::types::BinaryDecodable)]
});
attrs.push(parse_quote! {
#[cfg_attr(
feature = "json",
derive(opcua::types::JsonEncodable, opcua::types::JsonDecodable)
)]
});
attrs.push(parse_quote! {
#[cfg_attr(
feature = "xml",
derive(opcua::types::XmlEncodable, opcua::types::XmlDecodable, opcua::types::XmlType)
)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
});
let ty: Type = syn::parse_str(&item.typ.to_string())?;
attrs.push(parse_quote! {
Expand Down Expand Up @@ -581,22 +570,16 @@ impl CodeGenerator {
let mut attrs = Vec::new();
let mut fields = Punctuated::new();

attrs.push(parse_quote! {
#[opcua::types::ua_encodable]
});
if let Some(doc) = &item.documentation {
attrs.push(parse_quote! {
#[doc = #doc]
});
}
attrs.push(parse_quote! {
#[derive(Debug, Clone, PartialEq, opcua::types::BinaryEncodable, opcua::types::BinaryDecodable)]
});
attrs.push(parse_quote! {
#[cfg_attr(feature = "json", derive(opcua::types::JsonEncodable, opcua::types::JsonDecodable))]
});
attrs.push(parse_quote! {
#[cfg_attr(
feature = "xml",
derive(opcua::types::XmlEncodable, opcua::types::XmlDecodable, opcua::types::XmlType)
)]
#[derive(Debug, Clone, PartialEq)]
});

if self.has_default(&item.name) && !self.default_excluded.contains(&item.name) {
Expand Down
32 changes: 32 additions & 0 deletions async-opcua-macros/src/encoding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use json::{
generate_union_json_encode_impl,
};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::DeriveInput;
use unions::AdvancedEnum;
#[cfg(feature = "xml")]
Expand Down Expand Up @@ -190,3 +191,34 @@ pub fn generate_encoding_impl(
)),
}
}

pub(crate) fn derive_all_inner(item: DeriveInput) -> syn::Result<TokenStream> {
let input = EncodingInput::from_derive_input(item.clone())?;
let mut output = quote! {
#[derive(opcua::types::BinaryEncodable, opcua::types::BinaryDecodable)]
#[cfg_attr(
feature = "json",
derive(opcua::types::JsonEncodable, opcua::types::JsonDecodable)
)]
#[cfg_attr(
feature = "xml",
derive(
opcua::types::XmlEncodable,
opcua::types::XmlDecodable,
opcua::types::XmlType
)
)]
};

if matches!(input, EncodingInput::SimpleEnum(_)) {
output.extend(quote! {
#[derive(opcua::types::UaEnum)]
});
}

output.extend(quote! {
#item
});

Ok(output)
}
16 changes: 15 additions & 1 deletion async-opcua-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod encoding;
mod events;
mod utils;

use encoding::{generate_encoding_impl, EncodingToImpl};
use encoding::{derive_all_inner, generate_encoding_impl, EncodingToImpl};
use events::{derive_event_field_inner, derive_event_inner};
use proc_macro::TokenStream;
use syn::parse_macro_input;
Expand Down Expand Up @@ -185,3 +185,17 @@ pub fn derive_xml_type(item: TokenStream) -> TokenStream {
Err(e) => e.to_compile_error().into(),
}
}

#[proc_macro_attribute]
/// Derive all the standard encoding traits on this struct or enum.
/// This will derive `BinaryEncodable`, `BinaryDecodable`, `JsonEncodable`, `JsonDecodable`,
/// `XmlEncodable`, `XmlDecodable`, `XmlType`, and `UaEnum` if the type is a simple enum.
///
/// Normal attributes for those still apply. Note that the XML and JSON traits will
/// be behind `"xml"` and `"json"` feature gates respectively.
pub fn ua_encodable(_attr: TokenStream, item: TokenStream) -> TokenStream {
match derive_all_inner(parse_macro_input!(item)) {
Ok(r) => r.into(),
Err(e) => e.to_compile_error().into(),
}
}
16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/activate_session_request.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/activate_session_response.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_nodes_item.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_nodes_request.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_nodes_response.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_nodes_result.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_references_item.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_references_request.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions async-opcua-types/src/generated/types/add_references_response.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 815a87b

Please sign in to comment.