cppvtbl/
lib.rs

1#![no_std]
2
3extern crate self as cppvtbl;
4
5use core::{
6	marker::PhantomPinned,
7	mem,
8	ops::{Deref, DerefMut},
9	pin::Pin,
10};
11
12#[cfg(feature = "macros")]
13pub use cppvtbl_macros::{impl_vtables, vtable};
14
15#[repr(C)]
16pub struct WithVtables<T: HasVtables> {
17	vtables: T::Tables,
18	value: T,
19}
20impl<T: HasVtables> WithVtables<T> {
21	pub fn new(value: T) -> Self {
22		Self {
23			vtables: T::TABLES,
24			value,
25		}
26	}
27	pub fn vtables(&self) -> &T::Tables {
28		&self.vtables
29	}
30	/// Writing into vtables may cause UB
31	pub fn vtables_mut(&mut self) -> *mut T::Tables {
32		&mut self.vtables
33	}
34}
35impl<T: HasVtables> From<T> for WithVtables<T> {
36	fn from(value: T) -> Self {
37		Self::new(value)
38	}
39}
40impl<T: HasVtables> Deref for WithVtables<T> {
41	type Target = T;
42
43	fn deref(&self) -> &Self::Target {
44		&self.value
45	}
46}
47impl<T: HasVtables> DerefMut for WithVtables<T> {
48	fn deref_mut(&mut self) -> &mut Self::Target {
49		&mut self.value
50	}
51}
52
53pub unsafe trait HasVtables {
54	type Tables;
55	const TABLES: Self::Tables;
56}
57
58#[repr(transparent)]
59pub struct VtableRef<V: 'static>(&'static V, PhantomPinned);
60impl<V: 'static> VtableRef<V> {
61	/// Safety: constructed vtable should only be used by reference,
62	/// inside of WithVtables wrapper
63	pub const unsafe fn new(vtable: &'static V) -> Self {
64		Self(vtable, PhantomPinned)
65	}
66	pub fn table(&self) -> &'static V {
67		self.0
68	}
69	pub fn into_raw(v: &Self) -> *const VtableRef<V> {
70		v as *const _
71	}
72	pub fn into_raw_mut(v: Pin<&mut Self>) -> *mut VtableRef<V> {
73		// Safety: we returning pinned value as raw pointer,
74		// it is impossible to move data without using unsafe
75		unsafe { Pin::get_unchecked_mut(v) as *mut _ }
76	}
77	/// Safety: lifetime should be correctly specified
78	pub unsafe fn from_raw<'r>(raw: *const VtableRef<V>) -> &'r Self {
79		mem::transmute(raw as *const _ as *const Self)
80	}
81	/// Safety: lifetime should be correctly specified
82	pub unsafe fn from_raw_mut<'r>(raw: *mut VtableRef<V>) -> Pin<&'r mut Self> {
83		mem::transmute(raw as *mut _ as *mut Self)
84	}
85}
86
87pub trait HasVtable<V>: Sized + HasVtables {
88	fn get(from: &WithVtables<Self>) -> &VtableRef<V>;
89	// Vtable shouldn't be moved outside of owning struct, so it is wrapped in Pin
90	fn get_mut(from: &mut WithVtables<Self>) -> Pin<&mut VtableRef<V>>;
91}