3

I have a collection of interfaces that are loaded dynamically from shared libraries. I want to be able to convert those downcasted interfaces to their original type (trait).

struct A {}
fn abstract_a<'l>() -> &'l Any { return &A{} }

trait TargetTrait { fn some_method(); }
impl TargetTrait for A { fn some_method() { println!("HELLO"); } }    

fn main() {
    let x: &Any = abstract_a();
    let y: &TargetTrait = magic_conversion<&TargetTrait> (x);
}
// question: does 'magic_conversion'(or 'dynamic_cast') exist? what is it?

While loading these is not a problem, I have no idea how to get target functionality with such interface. In other words:

/* simplified for readability */
// this part is known
let some_lib = loadlib("path/to/lib.so")
let some_interface: &Any = some_lib.loadfunc<&Any>("constructor_func")()
    /* loader does not know what target type constructor has, so it presumes 'Any' */

// the problem:
let dependent_class = Some(class)
dependent_class.graphics = dynamic_cast<IGraphics>(some_interface)

In this example, dependent_class uses an extern interface and does not care about handling libloading and all of that complicated stuff. If there is another way to achieve my goal, I would also be very happy to see it, but the only solution I came up with is 'dynamic_cast'

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Can you rephrase *convert a type of elements in the collection to arbitrary(original) interface type (trait)*? Maybe a [mcve] would help. Is the shared library loading essential to the problem? – trent Feb 24 '18 at 02:54
  • @trentcl I don't think so. If I understand well, the OP wants a FFI with C++ – Boiethios Feb 24 '18 at 07:53
  • 1
    Use `x.downcast_ref().unwrap()` instead of `magic_conversion<&A>(x)`. No idea whether trait objects work across FFI-boundary; but certainly not with C++ (you need to forward every C++ type you want to recognize in Rust explicitly as a separate Rust type). – Stefan Feb 24 '18 at 10:02
  • @trentcl Boiethios is right, the problem is not with having a collection as it's presented in 'possible duplicate'. And yes, I intend to use _dynamic_cast_ during FFI, but with Rust shared lib, not C++, so there shouldn't be problems with recognition which Stefan mentioned –  Feb 24 '18 at 10:39
  • @OktavianClemens: Actually, it *is* a problem because Rust doesn't have a defined ABI. You'd have to ensure the shared library was compiled with the *exact* same compiler and compilation options, and all the transitive dependencies were exactly the same... at which point, you might as well just use static linking for all the difference it makes. Also, given that you appear to be trying to cast to an interface, I don't think what you want is possible. Rust doesn't have interfaces, and it doesn't have "cross casting" (*i.e.* between interfaces). I suspect more details might help. – DK. Feb 24 '18 at 10:41
  • @DK thank you for response, I didn't expect such complications with rust-to-rust FFI. But static linking is not an option, because the problem began with me trying to create "dynamic module loader" . For more details, I can provide [my C# implementation](https://github.com/Donaim/DModuler) of one such loader (trivial to achieve in c#). Also I've had an idea, to use [rust-libloading](https://github.com/Donaim/rust_libloading) 's `Symbol` and, for some reason, it worked for me on Linux, and didn't on Windows10 ( [code](https://github.com/Donaim/rust-first/tree/master/hello_dynamic) ). –  Feb 24 '18 at 11:28

1 Answers1

3

I think what you're looking for is downcast_ref::<A>:

let y: &TargetTrait = Any::downcast_ref::<A>(x).expect("Expected an A");

You have to specify the concrete type A. Any trait objects don't hold any information about what traits the underlying type implements, so you can't "cross-cast" from &Any to &TargetTrait directly; you have to know the underlying type.

The expect will panic if downcast_ref returns None; if that's not what you want, you have to decide what you want to happen when x is not an A and match against the result of downcast_ref instead.

trent
  • 25,033
  • 7
  • 51
  • 90