From 96c75c35713af106c798ab9578d70f958a1f1c76 Mon Sep 17 00:00:00 2001 From: numzero Date: Sun, 25 Oct 2026 13:22:41 +0300 Subject: [PATCH] use a vtable instead of direct linking --- ui/src/api.cxx | 45 ++------------------------- ui/src/api.hxx | 53 +++++++++++++++---------------- ui/src/lib.rs | 84 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 92 insertions(+), 90 deletions(-) diff --git a/ui/src/api.cxx b/ui/src/api.cxx index aaa2b64..a24b32c 100644 --- a/ui/src/api.cxx +++ b/ui/src/api.cxx @@ -4,54 +4,13 @@ #include namespace ffi { -extern "C" Core* rt4_viewport_create(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height); -extern "C" void rt4_viewport_destroy(Core* viewport); -extern "C" void rt4_viewport_configure(Core* viewport, std::uint32_t width, std::uint32_t height); -extern "C" void rt4_viewport_redraw(Core* viewport, const RedrawArgs* args); +extern "C" ICore* rt4_viewport_create(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height); } // namespace ffi -BoxCore::BoxCore(BoxCore&& b) - : ptr(std::exchange(b.ptr, {})) { -} - -BoxCore::~BoxCore() { - reset(); -} - -BoxCore& BoxCore::operator=(BoxCore&& b) { - if (&b == this) - return *this; - std::swap(ptr, b.ptr); - b.reset(); - return *this; -} - BoxCore BoxCore::from_xcb(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height) { if (!connection) throw std::logic_error("attempt to use a null connection"); if (!window) throw std::logic_error("attempt to use a null window"); - BoxCore out; - out.ptr.ptr = ffi::rt4_viewport_create(connection, window, width, height); - return out; -} - -void BoxCore::reset() { - auto viewport = std::exchange(ptr, {}); - if (viewport) - ffi::rt4_viewport_destroy(viewport.use()); -} - -ffi::Core* MutCore::use() const { - if (!ptr) - throw std::logic_error("attempt to use a null Core"); - return ptr; -} - -void MutCore::configure(std::uint32_t width, std::uint32_t height) const { - rt4_viewport_configure(use(), width, height); -} - -void MutCore::redraw(const RedrawArgs& args) const { - rt4_viewport_redraw(use(), &args); + return BoxCore{ffi::rt4_viewport_create(connection, window, width, height)}; } diff --git a/ui/src/api.hxx b/ui/src/api.hxx index 82d9880..71b16e7 100644 --- a/ui/src/api.hxx +++ b/ui/src/api.hxx @@ -2,15 +2,32 @@ #include +#include + struct xcb_connection_t; +class IBoxed { + friend struct BoxDeleter; + +private: + ~IBoxed() = delete; + virtual void destroy() = 0; +}; + +struct BoxDeleter { + void operator()(IBoxed* obj) { + obj->destroy(); + } +}; + +template +using Box = std::unique_ptr; + struct alignas(16) Vec4 { float x, y, z, w; }; namespace ffi { -struct Core; - struct RedrawArgs { float cam_yaw; float cam_pitch; @@ -21,36 +38,14 @@ struct RedrawArgs { using ffi::RedrawArgs; -class MutCore { - friend class BoxCore; - +class ICore : public IBoxed { public: - explicit operator bool() const { return ptr; } - - void configure(std::uint32_t width, std::uint32_t height) const; - void redraw(const RedrawArgs& args) const; - -private: - ffi::Core* ptr = nullptr; - ffi::Core* use() const; + virtual void configure(std::uint32_t width, std::uint32_t height) = 0; + virtual void redraw(const RedrawArgs& args) = 0; }; -class BoxCore { +class BoxCore : public Box { public: - BoxCore() = default; - BoxCore(const BoxCore&) = delete; - BoxCore(BoxCore&&); - BoxCore& operator=(const BoxCore&) = delete; - BoxCore& operator=(BoxCore&&); - ~BoxCore(); - - explicit operator bool() const { return !!ptr; } - const MutCore* operator->() const { return &ptr; } - - void reset(); - + using Box::Box; static BoxCore from_xcb(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height); - -private: - MutCore ptr; }; diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 571ecd9..62cabac 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -4,11 +4,74 @@ use PROJECT_NAME::{Core, RedrawArgs, init_gpu_inner}; use glam::{UVec2, uvec2}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle, XcbDisplayHandle, XcbWindowHandle}; +use crate::vtable::ICoreImpl; + +mod vtable { + use std::ops::{Deref, DerefMut}; + + use PROJECT_NAME::{Core, RedrawArgs}; + use glam::uvec2; + + #[repr(C)] + struct ICoreVTable { + destroy: unsafe extern "C" fn(this: Box), + configure: unsafe extern "C" fn(this: &mut ICoreImpl, width: u32, height: u32), + redraw: unsafe extern "C" fn(this: &mut ICoreImpl, args: &RedrawArgs), + } + + unsafe extern "C" fn destroy(this: Box) { + drop(this); + } + + unsafe extern "C" fn configure(this: &mut ICoreImpl, width: u32, height: u32) { + this.core.configure(uvec2(width, height)); + } + + unsafe extern "C" fn redraw(this: &mut ICoreImpl, args: &RedrawArgs) { + this.core.redraw(args); + } + + static VTABLE: ICoreVTable = ICoreVTable { + destroy: destroy, + configure: configure, + redraw: redraw, + }; + + #[repr(C)] + pub(crate) struct ICoreImpl { + vtable: &'static ICoreVTable, + core: Core, + } + + impl ICoreImpl { + pub(crate) fn new(core: Core) -> Box { + Box::new(ICoreImpl { + vtable: &VTABLE, + core, + }) + } + } + + impl DerefMut for ICoreImpl { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.core + } + } + + impl Deref for ICoreImpl { + type Target = Core; + + fn deref(&self) -> &Self::Target { + &self.core + } + } +} + unsafe fn create_viewport( display: impl Into, window: impl Into, size: UVec2, -) -> Box { +) -> Box { let target = wgpu::SurfaceTargetUnsafe::RawHandle { raw_display_handle: display.into(), raw_window_handle: window.into(), @@ -17,7 +80,7 @@ unsafe fn create_viewport( instance.create_surface_unsafe(target) })) .unwrap(); - Box::new(Core::new(gpu, size)) + ICoreImpl::new(Core::new(gpu, size)) } #[unsafe(no_mangle)] @@ -26,23 +89,8 @@ unsafe extern "C" fn rt4_viewport_create( window: NonZero, width: u32, height: u32, -) -> Box { +) -> Box { let display = XcbDisplayHandle::new(Some(connection), 0); let window = XcbWindowHandle::new(window); unsafe { create_viewport(display, window, uvec2(width, height)) } } - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_destroy(viewport: Box) { - drop(viewport); -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_configure(viewport: &mut Core, width: u32, height: u32) { - viewport.configure(uvec2(width, height)); -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_redraw(viewport: &mut Core, args: &RedrawArgs) { - viewport.redraw(args); -}