Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delegate directly from Box<T>, Arc<T>, etc. #68

Open
musjj opened this issue Oct 16, 2024 · 1 comment
Open

Delegate directly from Box<T>, Arc<T>, etc. #68

musjj opened this issue Oct 16, 2024 · 1 comment

Comments

@musjj
Copy link

musjj commented Oct 16, 2024

Is there a way to delegate traits directly from Box<T>, Arc<T>, etc. without a wrapper? For example, something like the following:

#[delegatable_trait(for = "Box<T>")]
trait Foo {
    fn hello(&self) -> String;
}

Will generate something like this:

trait Foo {
    fn hello(&self) -> String;
}

impl<T: Foo> Foo for Box<T> {
    fn hello(&self) -> String {
        (**self).hello()
    }
}
@dewert99
Copy link
Collaborator

Yes it is possible by using delegate_to_remote_methods which allows foreign types to delegate to arbitrary methods. For example, in your case you could use:

use ambassador::{delegatable_trait, delegate_to_remote_methods};
use std::ops::Deref;

#[delegatable_trait]
trait Foo {
    fn hello(&self) -> String;
}

#[delegate_to_remote_methods]
#[delegate(Foo, target_ref = "deref")]
impl<T> Box<T> {
    fn deref(&self) -> &T;
}

If your trait includes methods with owned self or mutable reference &mut self receivers you would also need to specify target_mut and target_owned. For example:

use ambassador::{delegatable_trait, delegate_to_remote_methods};
use std::ops::{Deref, DerefMut};

#[delegatable_trait]
trait Foo {
    fn hello(&self) -> String;

    fn consume(self);

    fn mutate(&mut self);
}

trait IntoInner: Deref {
    fn into_inner(self) -> Self::Target;
}

// Unfortunately Box doesn't already have a method for this so we need to add one
impl<T> IntoInner for Box<T> {
    fn into_inner(self) -> Self::Target {
        *self
    }
}

#[delegate_to_remote_methods]
#[delegate(Foo, target_ref = "deref", target_mut = "deref_mut", target_owned = "into_inner")]
impl<T> Box<T> {
    fn deref(&self) -> &T;
    fn deref_mut(&mut self) -> &mut T;
    fn into_inner(self) -> T;
}

If you have multiple traits you want to delegate, you can use the delegate attribute multiple times under the same delegate_to_remote_methods to reuse the impl block.

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

No branches or pull requests

2 participants