blob: a5fea8d013e8eb2945f10014d4c478e2433a1ad5 [file] [edit]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#![feature(negative_impls)]
//! # Object-Oriented Programming Support (OOPS).
//!
//! ## Upcasting
//!
//! To cast a reference or pointer to its base class type, use `.upcast()` when the base class is
//! not virtual, use `.virtual_upcast()` on raw pointers when the base class is virtual.
//!
//! For example:
//!
//! ```ignore
//! let x : *mut Derived = ...;
//! let y : *mut Base = x.upcast();
//! let z : *mut VirtualBase = x.virtual_upcast();
//! ```
//!
//! To implement upcasting, implement the `Inherits` trait for non-virtual bases and
//! `InheritsVirtual` for virtual bases.
//!
//! ## Downcasting
//!
//! TODO(b/216195042): dynamic downcasting
//! TODO(b/216195042): static downcasting
/// Trait for upcasting a Derived class to its non-virtual Base class.
///
/// # Safety
///
/// Implementations of `Upcast` must guarantee that they fulfill the safety promises of `upcast`.
pub unsafe trait Upcast<Target> {
/// Upcasts `self` to the target `Base` type.
///
/// # Safety
///
/// If `self` is a raw pointer, `self` must be a valid, dereferenceable pointer to an
/// initialized object of the derived class.
///
/// # Safety promises
///
/// If `self` is a valid pointer or reference, the returned target will be a valid, properly
/// aligned, and dereferenceable pointer or reference to the `Target` base subobject within
/// `self`, with the same lifetime as of `self`.
unsafe fn upcast(self) -> Target;
}
/// Upcast `*const` -> `*const`.
///
/// # Safety
///
/// Implementing upcast for converting `Derived` ptr to `Base` ptr is safe, because for a valid
/// Derived pointer, Inherits promises to return a valid base object inside Derived.
unsafe impl<Derived, Base> Upcast<*const Base> for *const Derived
where
Derived: Inherits<Base>,
{
unsafe fn upcast(self: *const Derived) -> *const Base {
// SAFETY: By the safety contract of `Upcast::upcast`, `self` is a valid,
// dereferenceable pointer to a `Derived` object, which satisfies the safety
// contract of `Derived::upcast_ptr`.
unsafe { Derived::upcast_ptr(self) }
}
}
/// Upcast `*mut` -> `*mut`.
///
/// # Safety
///
/// Implementing upcast for converting `Derived` ptr to `Base` ptr is safe, because for a valid
/// Derived pointer, Inherits promises to return a valid base object inside Derived.
unsafe impl<Derived, Base> Upcast<*mut Base> for *mut Derived
where
Derived: Inherits<Base>,
{
unsafe fn upcast(self: *mut Derived) -> *mut Base {
// SAFETY: By the safety contract of `Upcast::upcast`, `self` is a valid,
// dereferenceable pointer to a `Derived` object, which satisfies the safety
// contract of `Derived::upcast_ptr_mut`.
unsafe { Derived::upcast_ptr_mut(self) }
}
}
/// Upcast `&` -> `&`.
///
/// # Safety
///
/// Implementing upcast for converting `Derived` ptr to `Base` ptr is safe, because for a valid
/// Derived reference, Inherits promises to return a valid base object inside Derived.
unsafe impl<'a, Derived, Base> Upcast<&'a Base> for &'a Derived
where
Derived: Inherits<Base>,
{
unsafe fn upcast(self: &'a Derived) -> &'a Base {
// SAFETY: By the safety contract of `Upcast::upcast`, `self` is a valid reference
// to a `Derived` object, which satisfies the safety contract of `Derived::upcast_ptr`.
unsafe { &*Derived::upcast_ptr(self as *const Derived) }
}
}
/// Upcast a raw pointer. `Derived : Inherits<Base>` means that `Derived` can
/// be upcast to `Base`.
///
/// # Safety
///
/// Implementations must uphold the safety contract and safety promises requirement mentioned
/// on associated methods of this trait.
pub unsafe trait Inherits<Base> {
/// Upcast a `const` pointer.
///
/// # Safety
///
/// `derived` must be a valid, dereferenceable pointer to a `Self`.
///
/// # Safety promises
///
/// - If `derived` is a valid, dereferenceable pointer to a `Self`, this returns a valid,
/// properly aligned, and dereferenceable pointer to the `Base` subobject within `derived`.
unsafe fn upcast_ptr(derived: *const Self) -> *const Base;
/// Upcast a `mut` pointer.
///
/// # Safety
///
/// `derived` must be a valid, dereferenceable pointer to a `Self`.
///
/// # Safety promises
///
/// - If `derived` is a valid, dereferenceable pointer to a `Self`, this returns a valid,
/// properly aligned, and dereferenceable pointer to the `Base` subobject within `derived`.
unsafe fn upcast_ptr_mut(derived: *mut Self) -> *mut Base {
// SAFETY: This function has the same safety contract as `Self::upcast_ptr`.
unsafe { Self::upcast_ptr(derived) as *mut _ }
}
}
/// All classes are their own improper base.
unsafe impl<T> Inherits<T> for T {
unsafe fn upcast_ptr(derived: *const Self) -> *const Self {
derived
}
}
/// Trait for upcasting a Derived class pointer to its virtual Base class.
///
/// # Safety
///
/// Implementations of `VirtualUpcast` must guarantee that they fulfill the safety promises of
/// `virtual_upcast`.
pub unsafe trait VirtualUpcast<Target> {
/// Upcasts `self` to the target virtual base pointer type.
///
/// # Safety
///
/// The caller must ensure that if `self` is a ptr, it is either null or valid, dereferenceable
/// pointer to an initialized object of the derived class.
///
/// # Safety promises
///
/// If `self` is a valid pointer or reference, the returned target will be a valid, properly
/// aligned, and dereferenceable pointer or reference to the `Target` base subobject within
/// `self`.
unsafe fn virtual_upcast(self) -> Target;
}
/// Upcast `*const` -> `*const` for virtual base class.
unsafe impl<Derived, Base> VirtualUpcast<*const Base> for *const Derived
where
Derived: InheritsVirtual<Base>,
{
unsafe fn virtual_upcast(self: *const Derived) -> *const Base {
// SAFETY: By the safety contract of `VirtualUpcast::virtual_upcast`, `self` is
// either null or a valid, dereferenceable pointer to a `Derived` object, which
// satisfies the safety contract of `Derived::upcast_ptr_to_virtual_base`.
unsafe { Derived::upcast_ptr_to_virtual_base(self) }
}
}
/// Upcast `*mut` -> `*mut` for virtual base class.
unsafe impl<Derived, Base> VirtualUpcast<*mut Base> for *mut Derived
where
Derived: InheritsVirtual<Base>,
{
unsafe fn virtual_upcast(self: *mut Derived) -> *mut Base {
// SAFETY: By the safety contract of `VirtualUpcast::virtual_upcast`, `self` is
// either null or a valid, dereferenceable pointer to a `Derived` object, which
// satisfies the safety contract of `Derived::upcast_ptr_mut_to_virtual_base`.
unsafe { Derived::upcast_ptr_mut_to_virtual_base(self) }
}
}
/// Unsafely upcast a raw pointer to its virtual base class. `Derived : InheritsVirtual<Base>`
/// means that `Derived` can be upcast to `Base`.
///
/// To upcast in safe code, use the `VirtualUpcast` trait. `InheritsVirtual` is used for
/// unsafe pointer upcasts, and to implement upcasting.
///
/// # Safety
///
/// Implementations must uphold the safety contract and safety promises of the
/// unsafe functions in this trait.
pub unsafe trait InheritsVirtual<Base> {
/// Upcast a `const` pointer.
///
/// # Safety
///
/// `derived` must be a valid, dereferenceable pointer to a `Self`, or null.
///
/// # Safety promises
///
/// - If `derived` is null, this returns a null pointer.
/// - If `derived` is a valid, dereferenceable pointer to a `Self`, this returns a valid,
/// properly aligned, and dereferenceable pointer to the `Base` virtual base subobject within
/// `derived`, with the same lifetime as `derived`.
unsafe fn upcast_ptr_to_virtual_base(derived: *const Self) -> *const Base;
/// Upcast a `mut` pointer.
///
/// # Safety
///
/// `derived` must be a valid, dereferenceable pointer to a `Self`, or null.
///
/// # Safety promises
///
/// - If `derived` is null, this returns a null pointer.
/// - If `derived` is a valid, dereferenceable pointer to a `Self`, this returns a valid,
/// properly aligned, and dereferenceable pointer to the `Base` virtual base subobject within
/// `derived`, with the same lifetime as `derived`.
unsafe fn upcast_ptr_mut_to_virtual_base(derived: *mut Self) -> *mut Base {
// SAFETY: This function has the same safety contract as `Self::upcast_ptr_to_virtual_base`.
unsafe { Self::upcast_ptr_to_virtual_base(derived) as *mut _ }
}
}
/// All classes are their own improper base.
unsafe impl<T> InheritsVirtual<T> for T {
unsafe fn upcast_ptr_to_virtual_base(derived: *const Self) -> *const Self {
derived
}
}
#[cfg(test)]
mod test {
use super::*;
use googletest::gtest;
fn ptr_location<T: std::ops::Deref>(x: T) -> usize {
&*x as *const _ as *const u8 as usize
}
#[gtest]
fn test_unpin_upcast() {
#[derive(Default)]
struct Base(i32);
#[derive(Default)]
struct Derived {
_other_field: u32,
base: Base,
}
unsafe impl Inherits<Base> for Derived {
unsafe fn upcast_ptr(derived: *const Self) -> *const Base {
// SAFETY: `derived` is a valid pointer to a `Derived` value.
unsafe { &(*derived).base }
}
}
let mut derived = Derived::default();
// SAFETY: `derived` is a valid pointer to a `Derived` value.
assert_eq!(ptr_location(&derived.base), unsafe {
ptr_location::<&Base>((&derived).upcast())
});
let _: *const Base = unsafe { Derived::upcast_ptr(&derived) };
let _: *mut Base = unsafe { Derived::upcast_ptr_mut(&mut derived) };
// SAFETY: `derived` is a valid pointer to a `Derived` value.
unsafe {
let _: *const Base = (&derived as *const Derived).upcast();
let _: *mut Base = (&mut derived as *mut Derived).upcast();
}
// let _: &mut Base = (&mut derived).upcast(); // does not compile
// let _: Pin<&mut Base> = (&mut derived).upcast(); // does not compile
// let _: Pin<&mut Base> = Pin::new(&mut derived).upcast(); // does not compile
// This write must not be UB:
// SAFETY: `derived` is a valid pointer to a `Derived` value. `base` is a
// valid pointer to a `Base` value.
unsafe {
let base: *mut Base = (&mut derived as *mut Derived).upcast();
(*base).0 = 42;
}
assert_eq!(derived.base.0, 42);
}
#[gtest]
fn test_nonunpin_upcast() {
#[derive(Default)]
struct Base(i32);
impl !Unpin for Base {}
#[derive(Default)]
struct Derived {
_other_field: u32,
base: Base,
}
impl Unpin for Derived {}
unsafe impl Inherits<Base> for Derived {
unsafe fn upcast_ptr(derived: *const Self) -> *const Base {
// SAFETY: `derived` is a valid pointer to a `Derived` value.
unsafe { &(*derived).base }
}
}
let mut derived = Derived::default();
// SAFETY: `derived` is a valid pointer to a `Derived` value.
assert_eq!(ptr_location(&derived.base), unsafe {
ptr_location::<&Base>((&derived).upcast())
});
let _: *const Base = unsafe { Derived::upcast_ptr(&derived) };
let _: *mut Base = unsafe { Derived::upcast_ptr_mut(&mut derived) };
// let _: &mut Base = (&mut derived).upcast(); // does not compile
// let _: Pin<&mut Base> = (&mut derived).upcast(); // does not compile
// let _: Pin<&mut Base> = Pin::new(&mut derived).upcast(); // does not compile
// This write must not be UB:
{
let base: *mut Base = unsafe { Derived::upcast_ptr_mut(&mut derived) };
// SAFETY: `base` is a valid pointer to a `Base` value.
unsafe { (*base).0 = 42 };
}
assert_eq!(derived.base.0, 42);
}
}