egui_cable 0.9.0

A generic and extensible data-oriented widget for connecting ports by cables
Documentation
use std::any::Any;
use std::fmt::Debug;

use egui::Widget;

pub struct CustomWidget {
    widget: Box<dyn Any + Send + Sync + 'static>,
    debug: fn(&dyn Any) -> &dyn Debug,
    ui: fn(Box<dyn Any>, &mut egui::Ui) -> egui::Response,
}

fn debug<T: Debug + 'static>(t: &dyn Any) -> &dyn Debug {
    t.downcast_ref::<T>().unwrap()
}

fn ui<T: Widget + 'static>(widget: Box<dyn Any>, ui: &mut egui::Ui) -> egui::Response {
    widget.downcast::<T>().unwrap().ui(ui)
}

impl Debug for CustomWidget {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let debug = self.debug;
        f.debug_struct("CustomWidget")
            .field("widget", debug(&self.widget))
            .finish()
    }
}

// Cannot implement Widget for CustomWidget because it causes a conflict implementation with the following impl From<T>.
impl CustomWidget {
    pub(crate) fn ui(self, ui: &mut egui::Ui) -> egui::Response {
        let ui_fn = self.ui;
        ui_fn(self.widget, ui)
    }
}

impl<T: Widget + Debug + Send + Sync + 'static> From<T> for CustomWidget {
    fn from(widget: T) -> Self {
        CustomWidget {
            widget: Box::new(widget),
            debug: debug::<T>,
            ui: ui::<T>,
        }
    }
}