eclipse-uprotocol / up-rust

uProtocol Language Specific Library for Rust
Apache License 2.0
11 stars 9 forks source link

`UTransport::registerListener()` using marker trait dispatch for message types + generic #60

Closed PLeVasseur closed 6 months ago

PLeVasseur commented 6 months ago

Hey there folks :wave:

After chatting with @tamarafischer and @stevenhartley and reading through the equivalent PR over on up-java, I tried my hand at something similar over here in Rust.

This is very much in draft status to garner feedback! :slightly_smiling_face:

Some Design Considerations

(examples shamelessly ctrl+c, ctrl+v'ed from Chat-Gippity)

Downcasting + Any

use std::any::Any;

pub trait SuperTrait: Any {
    fn as_any(&self) -> &dyn Any;
}

pub trait SubTrait1: SuperTrait {}
pub trait SubTraitN: SuperTrait {}

impl dyn SuperTrait {
    fn downcast_ref<T: SuperTrait + 'static>(&self) -> Option<&T> {
        self.as_any().downcast_ref::<T>()
    }
}

Pros:

Cons:

TypeTag / Discriminants

pub trait SuperTrait {
    fn type_tag(&self) -> TypeTag;
}

enum TypeTag {
    SubTrait1,
    SubTraitN,
    // Other subtraits...
}

Pros:

Cons:

Visitor Pattern

pub trait SuperTrait {
    // Method for accepting a visitor. The visitor is an implementation of
    // a trait that will perform operations specific to the type of the object.
    fn accept(&self, visitor: &dyn Visitor);
}

pub trait SubTrait1: SuperTrait {}
pub trait SubTraitN: SuperTrait {}

pub trait Visitor {
    fn visit_sub_trait1(&self, element: &dyn SubTrait1);
    fn visit_sub_trait_n(&self, element: &dyn SubTraitN);
    // Add methods for other subtraits as needed
}

struct ConcreteSubTrait1;
impl SuperTrait for ConcreteSubTrait1 {
    fn accept(&self, visitor: &dyn Visitor) {
        visitor.visit_sub_trait1(self);
    }
}
impl SubTrait1 for ConcreteSubTrait1 {}

struct ConcreteSubTraitN;
impl SuperTrait for ConcreteSubTraitN {
    fn accept(&self, visitor: &dyn Visitor) {
        visitor.visit_sub_trait_n(self);
    }
}
impl SubTraitN for ConcreteSubTraitN {}

struct MyVisitor;

impl Visitor for MyVisitor {
    fn visit_sub_trait1(&self, _element: &dyn SubTrait1) {
        println!("SubTrait1 visited");
    }

    fn visit_sub_trait_n(&self, _element: &dyn SubTraitN) {
        println!("SubTraitN visited");
    }
    // Implement other visit methods as needed
}

Pros

Cons

Enum containing trait objects (the solution in this PR)

Pros

Cons

PLeVasseur commented 6 months ago

Closing this PR, we're going with another solution