Uh oh!
There was an error while loading. Please reload this page.
Refactor protobuf ser/de traits to allow decorator pattern - #19267
Refactor protobuf ser/de traits to allow decorator pattern#19267adriangb wants to merge 6 commits into
Conversation
milenkovicm
commented
Dec 10, 2025
I find the requirement to implement those four methods a bit confusing and the increasing API complexity unnecessary, ("we have defaults for you but we force you to implement it yourself"). No perfect solutions apparently anyway, lets give @timsaucer chance to have a look |
adriangb
commented
Dec 10, 2025
Yes agreed it's unfortunate but I don't see any way around it. It's just a limitation of Rust. |
milenkovicm
commented
Dec 12, 2025
@adriangb do you need before and after interception points for encode and decode or you could work with |
I think it’s useful to be able to control if the default serializer is called or not. For example in the case of caching Arc’ed stuff you want to check the cache, delegate to the default, and then cache after. I also don’t think that would help the recursiveness: you’d still have to in the default implementation pass a reference to Would it help if we provided a macro to implement the defaults? |
milenkovicm
commented
Dec 12, 2025
I agree with you it's hard problem to crack. Would or if I'm just throwing ideas, trying to help, will have a look tomorrow |
adriangb
commented
Dec 12, 2025
Maybe something similar to the TreeNode API would work? |
milenkovicm
commented
Dec 12, 2025
just rough idea, this goes to encoder: fnbefore_encode_expr(&self,_node:&Arc<dynPhysicalExpr>,) -> Result<Option<protobuf::PhysicalExprNode>>{Ok(None)}I don't like use of this part is pubfnserialize_physical_expr(value:&Arc<dynPhysicalExpr>,codec:&dynPhysicalExtensionCodec,) -> Result<protobuf::PhysicalExprNode>{match codec.before_encode_expr(value)? {Some(p) => Ok(p),None => serialize_physical_expr(value, codec),}}maybe tree node like approach may make sense as well |
timsaucer
commented
Dec 17, 2025
This feels like it's more complicated than it needs to be. But I also must be missing something because I still don't see what it was that my original proposal in #18813 didn't meet the needs. I think you have some use cases and context in mind @adriangb that I clearly don't understand. Regarding this PR, do you also need to cover the other functions in the codec? We now have two methods we need for physical plans, I think the problem we're running into with not having an elegant way of hooking these together is demonstrating there's a friction point between what the codec is for and what the protobuf processing part is for. I'm sure I'm biased towards my initial implementation approach, but I still feel that's a cleaner way of doing it. |
fcbe455 to
0026efeCompare@timsaucer thank you for taking a look at this. I have my two key use cases as examples in this PR. When I first looked at your change it seemed like it would not be able to implement these examples, but I can give it another try to see if they can be made to work with your proposal. |
adriangb
commented
Jan 27, 2026
Closing in favor of #19437 |
Refactor PhysicalExtensionCodec with &dyn dispatch (Alternative to #19234)
Which issue does this PR close?
Closes#18477
Related to #19234 - this PR provides an alternative implementation approach.
Rationale for this change
DataFusion's protobuf serialization system currently has limited interception points. The existing PhysicalExtensionCodec
trait only provides hooks for custom extensions (try_decode/try_encode) and unknown expressions
(try_decode_expr/try_encode_expr), but users cannot intercept serialization of all plan and expression nodes.
This limitation prevents important use cases:
PR #19234 addresses this by switching from &dyn PhysicalExtensionCodec to generics (&C where C: PhysicalExtensionCodec +
?Sized). However, #19234 (comment) raised concerns about FFI
compatibility, since distributed systems and FFI boundaries often require dynamic dispatch.
What changes are included in this PR?
This PR takes an alternative approach: keep &dyn dispatch but add 4 new required methods that intercept every
plan/expression node during serialization:
Key implementation details:
Comparison with PR #19234
Pros of this approach:
Cons of this approach:
Files changed
Migration example
For existing implementations that don't need custom interception: