feat(codegen): integrated logging

This commit is contained in:
Nova
2025-08-29 10:31:04 -07:00
parent b95ea8e90f
commit 8e9ac71ebb
3 changed files with 62 additions and 42 deletions

8
Cargo.lock generated
View File

@@ -5399,12 +5399,6 @@ dependencies = [
"bitflags 2.9.1", "bitflags 2.9.1",
] ]
[[package]]
name = "split-iter"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d"
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@@ -5515,10 +5509,8 @@ name = "stardust-xr-server-codegen"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"mint",
"proc-macro2", "proc-macro2",
"quote", "quote",
"split-iter",
"stardust-xr", "stardust-xr",
] ]

View File

@@ -9,8 +9,6 @@ proc-macro = true
[dependencies] [dependencies]
convert_case = "0.6.0" convert_case = "0.6.0"
quote = "1.0.33" quote = "1.0.33"
mint = "0.5.9"
proc-macro2 = "1.0.71" proc-macro2 = "1.0.71"
split-iter = "0.1.0"
stardust-xr = { workspace = true } stardust-xr = { workspace = true }

View File

@@ -1,7 +1,6 @@
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use split_iter::Splittable;
use stardust_xr::schemas::protocol::*; use stardust_xr::schemas::protocol::*;
fn fold_tokens(a: TokenStream, b: TokenStream) -> TokenStream { fn fold_tokens(a: TokenStream, b: TokenStream) -> TokenStream {
@@ -183,14 +182,18 @@ fn generate_custom_struct(custom_struct: &CustomStruct) -> TokenStream {
fn generate_aspect(aspect: &Aspect) -> TokenStream { fn generate_aspect(aspect: &Aspect) -> TokenStream {
let description = &aspect.description; let description = &aspect.description;
let (client_members, server_members) = aspect.members.iter().split(|m| m.side == Side::Server); let (client_members, server_members) = aspect
.members
.iter()
.partition::<Vec<_>, _>(|m| m.side == Side::Client);
let client_mod_name = Ident::new( let client_mod_name = Ident::new(
&format!("{}_client", &aspect.name.to_case(Case::Snake)), &format!("{}_client", &aspect.name.to_case(Case::Snake)),
Span::call_site(), Span::call_site(),
); );
let client_side_members = client_members let client_side_members = client_members
.map(|m| generate_member(aspect.id, &aspect.name.to_case(Case::Snake), m)) .into_iter()
.map(|m| generate_member(aspect.id, &aspect.name.to_case(Case::Pascal), m))
.reduce(fold_tokens) .reduce(fold_tokens)
.map(|t| { .map(|t| {
// TODO: properly import all dependencies // TODO: properly import all dependencies
@@ -228,6 +231,7 @@ fn generate_aspect(aspect: &Aspect) -> TokenStream {
let alias_info = generate_alias_info(aspect); let alias_info = generate_alias_info(aspect);
let server_side_members = server_members let server_side_members = server_members
.into_iter()
.map(|m| generate_member(aspect.id, &aspect.name.to_case(Case::Pascal), m)) .map(|m| generate_member(aspect.id, &aspect.name.to_case(Case::Pascal), m))
.reduce(fold_tokens) .reduce(fold_tokens)
.unwrap_or_default(); .unwrap_or_default();
@@ -378,6 +382,18 @@ fn generate_member(aspect_id: u64, aspect_name: &str, member: &Member) -> TokenS
} }
Side::Client => quote!(_node: &crate::nodes::Node), Side::Client => quote!(_node: &crate::nodes::Node),
}; };
let arguments = member
.arguments
.iter()
.map(|a| Ident::new(&a.name.to_case(Case::Snake), Span::call_site()));
let argument_debug = member
.arguments
.iter()
.map(|a| Ident::new(&a.name.to_case(Case::Snake), Span::call_site()))
.map(|n| quote!(?#n))
.reduce(|a, b| quote!(#a, #b))
.map(|args| quote!(#args,));
let argument_decls = member let argument_decls = member
.arguments .arguments
.iter() .iter()
@@ -402,12 +418,13 @@ fn generate_member(aspect_id: u64, aspect_name: &str, member: &Member) -> TokenS
quote! { quote! {
#[doc = #description] #[doc = #description]
pub fn #name(#argument_decls) -> crate::core::error::Result<()> { pub fn #name(#argument_decls) -> crate::core::error::Result<()> {
let arguments = (#argument_uses);
let (#(#arguments),*) = &arguments;
::tracing::trace!(#argument_debug "sent signal to client: {}::{}", #aspect_name, #name_str);
let result = stardust_xr::schemas::flex::serialize(&arguments).map_err(|e|e.into()).and_then(|serialized|_node.send_remote_signal(#aspect_id, #opcode, serialized));
let result = stardust_xr::schemas::flex::serialize((#argument_uses)).map_err(|e|e.into()).and_then(|serialized|_node.send_remote_signal(#aspect_id, #opcode, serialized));
if let Err(err) = result.as_ref() { if let Err(err) = result.as_ref() {
::tracing::warn!("failed to send remote signal: {}::{}, error: {}",#aspect_name,#name_str,err); ::tracing::warn!(#argument_debug "failed to send signal to client : {}::{}, error: {}",#aspect_name,#name_str,err);
} else {
::tracing::trace!("sent remote signal: {}::{}",#aspect_name,#name_str);
} }
result result
} }
@@ -417,11 +434,18 @@ fn generate_member(aspect_id: u64, aspect_name: &str, member: &Member) -> TokenS
quote! { quote! {
#[doc = #description] #[doc = #description]
pub async fn #name(#argument_decls) -> crate::core::error::Result<(#return_type, Vec<std::os::fd::OwnedFd>)> { pub async fn #name(#argument_decls) -> crate::core::error::Result<(#return_type, Vec<std::os::fd::OwnedFd>)> {
let result = _node.execute_remote_method_typed(#aspect_id, #opcode, &(#argument_uses), vec![]).await; let arguments = (#argument_uses);
if let Err(err) = result.as_ref() { let (#(#arguments),*) = &arguments;
::tracing::warn!("failed to call remote method: {}::{}, error: {}",#aspect_name,#name_str,err); ::tracing::trace!(#argument_debug "called client method: {}::{}",#aspect_name,#name_str);
} else { let result = _node.execute_remote_method_typed(#aspect_id, #opcode, &arguments, vec![]).await;
::tracing::trace!("called remote method: {}::{}",#aspect_name,#name_str);
match result.as_ref() {
Ok(value) => {
::tracing::trace!(?value, "client method returned value: {}::{}",#aspect_name,#name_str);
},
Err(err) => {
::tracing::warn!(#argument_debug "client method returned error: {}::{}, error: {}",#aspect_name,#name_str,err);
}
} }
result result
} }
@@ -444,6 +468,8 @@ fn generate_member(aspect_id: u64, aspect_name: &str, member: &Member) -> TokenS
fn generate_run_member(aspect_name: &Ident, _type: MemberType, member: &Member) -> TokenStream { fn generate_run_member(aspect_name: &Ident, _type: MemberType, member: &Member) -> TokenStream {
let opcode = member.opcode; let opcode = member.opcode;
let member_name_ident = Ident::new(&member.name, Span::call_site()); let member_name_ident = Ident::new(&member.name, Span::call_site());
let member_name = member_name_ident.to_string();
let aspect_name_str = aspect_name.to_string();
let argument_names = member let argument_names = member
.arguments .arguments
@@ -458,6 +484,13 @@ fn generate_run_member(aspect_name: &Ident, _type: MemberType, member: &Member)
generate_argument_type(&_type, a.optional, true) generate_argument_type(&_type, a.optional, true)
}) })
.reduce(|a, b| quote!(#a, #b)); .reduce(|a, b| quote!(#a, #b));
let argument_debug = member
.arguments
.iter()
.map(|a| Ident::new(&a.name.to_case(Case::Snake), Span::call_site()))
.map(|n| quote!(?#n))
.reduce(|a, b| quote!(#a, #b))
.map(|args| quote!(#args,));
// dbg!(&argument_types); // dbg!(&argument_types);
let deserialize = argument_names let deserialize = argument_names
.clone() .clone()
@@ -480,33 +513,30 @@ fn generate_run_member(aspect_name: &Ident, _type: MemberType, member: &Member)
.map(|a| generate_argument_deserialize(&a.name, &a._type, a.optional)) .map(|a| generate_argument_deserialize(&a.name, &a._type, a.optional))
.reduce(|a, b| quote!(#a, #b)) .reduce(|a, b| quote!(#a, #b))
.unwrap_or_default(); .unwrap_or_default();
let member_name = member_name_ident.to_string();
let aspect_name_str = aspect_name.to_string();
match _type { match _type {
MemberType::Signal => quote! { MemberType::Signal => quote! {
#opcode => { let result = (move || { #opcode => (move || {
#deserialize #deserialize
::tracing::trace!(#argument_debug "received local signal: {}::{}",#aspect_name_str,#member_name);
<Self as #aspect_name>::#member_name_ident(_node, _calling_client.clone(), #argument_uses) <Self as #aspect_name>::#member_name_ident(_node, _calling_client.clone(), #argument_uses)
})().map_err(|e: crate::core::error::ServerError| stardust_xr::scenegraph::ScenegraphError::MemberError { error: e.to_string() }); })().map_err(|e: crate::core::error::ServerError| stardust_xr::scenegraph::ScenegraphError::MemberError { error: e.to_string() }),
if let Err(err) = result.as_ref() {
::tracing::warn!("failed to receive local signal: {}::{}, error: {}",#aspect_name_str,#member_name,err);
} else {
::tracing::trace!("received local signal: {}::{}",#aspect_name_str,#member_name);
}
result
},
}, },
MemberType::Method => quote! { MemberType::Method => quote! {
#opcode => _method_response.wrap_async(async move { #opcode => _method_response.wrap_async(async move {
#deserialize #deserialize
let result = <Self as #aspect_name>::#member_name_ident(_node, _calling_client.clone(), #argument_uses).await; ::tracing::trace!(#argument_debug "called local method: {}::{}",#aspect_name_str,#member_name);
if let Err(err) = result.as_ref() { let result = <Self as #aspect_name>::#member_name_ident(_node, _calling_client.clone(), #argument_uses).await;
::tracing::warn!("failed to call local method: {}::{}, error: {}",#aspect_name_str,#member_name,err);
} else { match result.as_ref() {
::tracing::trace!("called local method: {}::{}",#aspect_name_str,#member_name); Ok(value) => {
}; ::tracing::trace!(?value, "client method returned value: {}::{}",#aspect_name_str,#member_name);
let result = result?; },
Ok((#serialize, Vec::<std::os::fd::OwnedFd>::new())) Err(err) => {
::tracing::warn!("client method returned error: {}::{}, error: {}",#aspect_name_str,#member_name,err);
}
}
let result = result?;
Ok((#serialize, Vec::<std::os::fd::OwnedFd>::new()))
}), }),
}, },
} }