emoon/ProDBG

Research ways to implement polymorphic functions in Ui

Closed this issue · 2 comments

Currently Ui contains functions that differ in parameter types. For example, there are four push_id functions:

    pub fn push_id_str(&self, s: &str) {
            let start = mem::transmute::<*const u8, *const i8>(s.as_ptr());
            let end = start.offset(self.len() as isize);
            ((*ui.api).push_id_str_range)(start, end);
    }

    pub fn push_id_usize(&self, id: usize) {
        unsafe { ((*self.api).push_id_ptr)(mem::transmute(id)) }
    }

    pub fn push_id_ptr<T>(&self, id: &T) {
        unsafe { ((*self.api).push_id_ptr)(mem::transmute(id)) }
    }

    pub fn push_id_int(&self, id: i32) {
        unsafe { ((*self.api).push_id_int)(id) }
    }

Is there a way to have single statically-dispatched method for this?

Without strings it could be done pretty easily:

pub trait UiId {
    fn push(&self, ui: &Ui);
}

impl UiId for i32 {
    fn push(&self, ui: &Ui) {
        unsafe {
            ((*ui.api).push_id_int)(*self)
        }
    }
}

impl<'a, T> UiId for &'a T {
    fn push(&self, ui: &Ui) {
        unsafe {
            ((*ui.api).push_id_ptr)(mem::transmute(&self))
        }
    }
}

impl Ui {
    ...
    pub fn push_id<T: UiId>(id: T) {
        id.push(self);
    }
    ...
}

This works pretty well and api behaviour is expected. However &str implementation can behave not as expected:

impl<'a> UiId for &'a str {
    fn push(&self, ui: &Ui) {
        unsafe {
            ...
        }
    }
}

If we call this with anything &str-like, reference-type will be used:

let x = "abc".to_string();
ui.push(&x);

This code will execute reference-type push_id which is unexpected behaviour. We could implement a broader version like this:

impl<'a, T: Into<&'a str>> UiId for T {
    fn push(&self, ui: &Ui) {
        unsafe {
            ...
        }
    }
}

But such an implementation forbids any other. So there is either one broad implementation or several implementations for concrete types.

emoon commented

I haven't used generic enough to know how to implement this. Maybe you could post this on the https://users.rust-lang.org forum and ask?

emoon commented

Switching Qt and C++ (for now, will be reevaluated when there are some good Rust bindings for Qt) so closing.