#traits #interface #object #query #dynamically #dynamic #type-erased

query_interface

Dynamically query a type-erased object for any trait implementation

8 releases

Uses old Rust 2015

0.3.5 Mar 24, 2018
0.3.4 Mar 23, 2018
0.3.3 Sep 8, 2016
0.2.0 Sep 4, 2016
0.1.0 Sep 4, 2016

#1906 in Rust patterns

Download history 48/week @ 2024-11-16 85/week @ 2024-11-23 95/week @ 2024-11-30 148/week @ 2024-12-07 129/week @ 2024-12-14 42/week @ 2024-12-21 24/week @ 2024-12-28 74/week @ 2025-01-04 83/week @ 2025-01-11 77/week @ 2025-01-18 34/week @ 2025-01-25 73/week @ 2025-02-01 100/week @ 2025-02-08 72/week @ 2025-02-15 136/week @ 2025-02-22 31/week @ 2025-03-01

354 downloads per month
Used in 37 crates (29 directly)

MIT/Apache

28KB
512 lines

query_interface

Dynamically query a type-erased object for any trait implementation

Documentation

Example:

#[macro_use]
extern crate query_interface;

use query_interface::{Object, ObjectClone};
use std::fmt::Debug;

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
struct Foo;

interfaces!(Foo: ObjectClone, Debug, Bar);

trait Bar {
    fn do_something(&self);
}
impl Bar for Foo {
    fn do_something(&self) {
        println!("I'm a Foo!");
    }
}

fn main() {
    let obj = Box::new(Foo) as Box<Object>;
    let obj2 = obj.clone();
    println!("{:?}", obj2);
   
    obj2.query_ref::<Bar>().unwrap().do_something();  // Prints: "I'm a Foo!"
}

In short, this allows you to pass around Objects and still have access to any of the (object-safe) traits implemented for the underlying type. The library also provides some useful object-safe equivalents to standard traits, including ObjectClone, ObjectPartialEq, ObjectPartialOrd, ObjectHash.

To improve usability, the non-object-safe versions of the traits are implemented directly on the Object trait object, allowing you to easily clone Objects and store them in collections.

You can have your own Object-like traits to enforce some additional static requirements by using the mopo! macro:

trait CustomObject : Object {
    ...
}
mopo!(CustomObject);

struct Foo;
interfaces!(Foo: CustomObject);

impl CustomObject for Foo {
    ...
}

Now you can use CustomObject in all the ways you could use Object.

With the "dynamic" feature, you can at runtime register additional traits to be queryable on a type. This allows you to bypass the normal coherence rules:

trait Custom {}
impl Custom for String {}

fn main() {
    dynamic_interfaces! {
        String: Custom;
    }
}

Dependencies