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.
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?
Switching Qt and C++ (for now, will be reevaluated when there are some good Rust bindings for Qt) so closing.