Skip to content

fix: support qualified types in topic handlers#344

Open
immanuwell wants to merge 1 commit into
dapr:mainfrom
immanuwell:fix/topic-qualified-types
Open

fix: support qualified types in topic handlers#344
immanuwell wants to merge 1 commit into
dapr:mainfrom
immanuwell:fix/topic-qualified-types

Conversation

@immanuwell

Copy link
Copy Markdown
Contributor

Description

#[topic] blows up if the handler arg uses a qualified type like serde_json::Value.

The macro was splitting tokens on : so serde_json::Value got treated like 2 inputs. This switches it to parse the function signature with syn, keeps the String fast path, and adds regression tests. tiny fix, but pretty real.

Repro:

#[topic(pub_sub_name = "pubsub", topic = "A")]
async fn handle_a_event(order: serde_json::Value) {}

Before:
cargo check panics with Expected to only have one input variable

After:
cargo check passes.

Issue reference

This PR will close #172

Checklist

  • Code compiles correctly
  • Created/updated tests
  • Extended the documentation

Signed-off-by: immanuwell <pchpr.00@list.ru>
@immanuwell
immanuwell requested review from a team as code owners June 20, 2026 08:15

@mikeee mikeee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favour of this change with a few changes, please could you clarify whether allowing non-stdlib definitions of String should be allowed as implemented?
I think for the string type assertion it'd be better if we asserted against the entire type path, something like this:

fn is_string_type(ty: &Type) -> bool {
    let Type::Path(type_path) = ty else {
        return false;
    };
    if type_path.qself.is_some() {
        return false;
    }

    let path = &type_path.path;
    let matches_path = |names: &[&str]| {
        path.segments.len() == names.len()
            && path
                .segments
                .iter()
                .zip(names)
                .all(|(seg, name)| seg.ident == *name && seg.arguments.is_empty())
    };

    matches_path(&["String"])
        || matches_path(&["std", "string", "String"])
        || matches_path(&["alloc", "string", "String"])
}

wdyt?

Comment thread dapr-macros/src/lib.rs
Comment on lines +247 to +248
.last()
.is_some_and(|segment| segment.ident == "String"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this intentionally added to allow String types defined by any other crates such as other_crate::String?

Comment thread dapr-macros/src/lib.rs
}

#[cfg(test)]
mod tests {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding tests, please enhance this with negative tests to confirm the above review assumptions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Pubsub function parameter does not allow additional colons

2 participants