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

portable-atomic-util: Example for Arc<dyn Trait> #143

Closed
piotrfila opened this issue Dec 17, 2023 · 3 comments
Closed

portable-atomic-util: Example for Arc<dyn Trait> #143

piotrfila opened this issue Dec 17, 2023 · 3 comments
Labels
A-portable-atomic-util Area: related to portable-atomic-util crate C-documentation Category: related to documentation. S-blocked Status: Blocked on something else

Comments

@piotrfila
Copy link

Hello,
I am trying to port a crate that uses Arc<dyn Trait> for dynamic dispatch to but I could not find a way to do this with this crate.
Minimal example:

trait MyTrait {
    fn do_stuff(&self, x: &mut u32);
}

struct Foo(u32);

impl MyTrait for Foo {
    fn do_stuff(&self, x: &mut u32) {
        *x = self.0;
    }
}

fn main()  {
    use portable_atomic_util::Arc;
    let arc = Arc::new(Foo(42)) as Arc<dyn MyTrait>;

    let mut x = 0;
    arc.do_stuff(&mut x);
}

The error I get: an 'as' expression can only be used to convert between primitive types or to coerce to a specific trait object.
This example works if use portable_atomic_util::Arc; is replaced with use alloc::sync::Arc;, though the latter is not available on my target architecture (thumbv6m),.
I also tried calling .into() and .try_into() on the Arc, as well as converting the Foo object like this:

    let arc = Arc::new(*(&Foo(42) as &dyn MyTrait));

but those methods work neither on this crate's Arc nor alloc's.

Is there a way to do this using this crate?

@taiki-e
Copy link
Owner

taiki-e commented Dec 18, 2023

Unfortunately, AFAIK, to make this work requires unstable CoerceUnsized trait (rust-lang/rust#18598).
See also the Rust reference.

Note: While the definition of the unsized coercions and their implementation has been stabilized, the traits themselves are not yet stable and therefore can't be used directly in stable Rust.

@taiki-e taiki-e added S-blocked Status: Blocked on something else A-portable-atomic-util Area: related to portable-atomic-util crate labels Dec 18, 2023
@taiki-e
Copy link
Owner

taiki-e commented Dec 21, 2023

Once #142 is merged EDIT: with portable-atomic-util 0.2 just released, conversion from Box is supported, so we can emulate CoerceUnsized with stable rustc via Box:

let boxed: Box<dyn ...> = Box::new(Foo(42));
let arc: Arc<dyn ...> = Arc::from(boxed);

However, the current rustc can omit the allocation of Box if T is Sized (https://godbolt.org/z/s49WxEcan), but unfortunately it cannot omit it if T is Unsized (https://godbolt.org/z/f55oWG1rW), so the generated code will not be the best.
EDIT: I noticed the compiler can optimize in the same way as using CoerceUnsized if the compiler can understand the actual size and/or metadata, even if T is unsized. e.g., Box<[T; N]> -> Box<[T]> -> Arc<[T]>. https://godbolt.org/z/qeajGhWvP

EDIT2: As for the Arc::new([T; N]) -> Arc<[T]> coercion, you can work around this by using Arc::from instead of Arc::new

// error
let x: Arc<[u32]> = Arc::new([1, 2, 3]);
// ok
let x: Arc<[u32]> = Arc::from([1, 2, 3]);

@taiki-e taiki-e changed the title Example for Arc<dyn Trait> portable-atomic-util: Example for Arc<dyn Trait> Dec 28, 2023
@taiki-e taiki-e added the C-documentation Category: related to documentation. label May 7, 2024
@taiki-e
Copy link
Owner

taiki-e commented May 7, 2024

This limitation is now documented with the link to the known workaround (a8cc61b).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-portable-atomic-util Area: related to portable-atomic-util crate C-documentation Category: related to documentation. S-blocked Status: Blocked on something else
Projects
None yet
Development

No branches or pull requests

2 participants