#![cfg_attr(not(test), no_std)]
extern crate alloc;
extern crate self as partial_this;
use alloc::{boxed::Box, rc::Rc, sync::Arc};
use core::mem::MaybeUninit;
pub use typenum;
pub use partial_this_macro::partial;
pub use uninit_this::*;
mod uninit_this {
use super::*;
pub trait UninitThis {
type Target;
type Inited;
unsafe fn get(&self) -> &MaybeUninit<Self::Target>;
unsafe fn get_mut(&mut self) -> &mut MaybeUninit<Self::Target>;
unsafe fn assume_init(self) -> Self::Inited;
}
impl<'a, T> UninitThis for &'a mut MaybeUninit<T> {
type Target = T;
type Inited = &'a mut T;
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn assume_init(self) -> Self::Inited {
unsafe { self.assume_init_mut() }
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get(&self) -> &MaybeUninit<Self::Target> {
self
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get_mut(&mut self) -> &mut MaybeUninit<Self::Target> {
self
}
}
impl<T> UninitThis for MaybeUninit<T> {
type Target = T;
type Inited = T;
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn assume_init(self) -> Self::Inited {
unsafe { self.assume_init() }
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get(&self) -> &MaybeUninit<Self::Target> {
self
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get_mut(&mut self) -> &mut MaybeUninit<Self::Target> {
self
}
}
impl<T> UninitThis for Box<MaybeUninit<T>> {
type Target = T;
type Inited = Box<T>;
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn assume_init(self) -> Self::Inited {
unsafe { self.assume_init() }
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get(&self) -> &MaybeUninit<Self::Target> {
self
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get_mut(&mut self) -> &mut MaybeUninit<Self::Target> {
self
}
}
impl<T> UninitThis for Rc<MaybeUninit<T>> {
type Target = T;
type Inited = Rc<T>;
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn assume_init(self) -> Self::Inited {
unsafe { self.assume_init() }
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get(&self) -> &MaybeUninit<Self::Target> {
self
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get_mut(&mut self) -> &mut MaybeUninit<Self::Target> {
Rc::get_mut(self).unwrap()
}
}
impl<T> UninitThis for Arc<MaybeUninit<T>> {
type Target = T;
type Inited = Arc<T>;
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn assume_init(self) -> Self::Inited {
unsafe { self.assume_init() }
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get(&self) -> &MaybeUninit<Self::Target> {
self
}
#[cfg_attr(not(debug_assertions), inline(always))]
unsafe fn get_mut(&mut self) -> &mut MaybeUninit<Self::Target> {
Arc::get_mut(self).unwrap()
}
}
}
pub trait PartialThis {
type Partial<N>;
fn partial<U>(this: U) -> Self::Partial<U>
where
U: UninitThis<Target = Self>;
}
pub trait ThisPtr {
type Target;
fn this(&self) -> &MaybeUninit<Self::Target>;
fn this_mut(&mut self) -> &mut MaybeUninit<Self::Target>;
}
impl<U: UninitThis> ThisPtr for U {
type Target = U::Target;
#[cfg_attr(not(debug_assertions), inline(always))]
fn this(&self) -> &MaybeUninit<Self::Target> {
unsafe { U::get(self) }
}
#[cfg_attr(not(debug_assertions), inline(always))]
fn this_mut(&mut self) -> &mut MaybeUninit<Self::Target> {
unsafe { U::get_mut(self) }
}
}
#[cfg(test)]
#[allow(nonstandard_style)]
pub mod test_reference {
use crate::PartialThis;
#[derive(Debug)]
pub struct Foo {
pub foo: i32,
pub bar: f32,
}
pub use should_be_generated_by_macro::*;
mod should_be_generated_by_macro {
use crate::ThisPtr;
#[derive(Debug)]
pub struct foo<N: ThisPtr<Target = super::Foo>>(N);
#[derive(Debug)]
pub struct bar<N: ThisPtr<Target = super::Foo>>(N);
impl<N: ThisPtr<Target = super::Foo>> ThisPtr for foo<N> {
type Target = super::Foo;
fn this(&self) -> &core::mem::MaybeUninit<Self::Target> {
self.0.this()
}
fn this_mut(&mut self) -> &mut core::mem::MaybeUninit<Self::Target> {
self.0.this_mut()
}
}
impl<N: ThisPtr<Target = super::Foo>> ThisPtr for bar<N> {
type Target = super::Foo;
fn this(&self) -> &core::mem::MaybeUninit<Self::Target> {
self.0.this()
}
fn this_mut(&mut self) -> &mut core::mem::MaybeUninit<Self::Target> {
self.0.this_mut()
}
}
impl<N: ThisPtr<Target = super::Foo>> Drop for foo<N> {
fn drop(&mut self) {
unsafe { core::ptr::drop_in_place(&mut (*self.0.this_mut().as_mut_ptr()).foo) };
}
}
impl<N: ThisPtr<Target = super::Foo>> Drop for bar<N> {
fn drop(&mut self) {
unsafe { core::ptr::drop_in_place(&mut (*self.0.this_mut().as_mut_ptr()).bar) };
}
}
pub use private::Partial as PartialFoo;
mod private {
use super::*;
use crate::{PartialThis, ThisPtr, UninitThis};
use core::mem::ManuallyDrop;
use core::ops::{BitAnd, BitOr};
use typenum::{Or, Shleft, U0, U1, U2, U3};
#[derive(Debug)]
pub struct Partial<N>(N);
impl PartialThis for super::super::Foo {
type Partial<N> = private::Partial<N>;
fn partial<U>(this: U) -> Self::Partial<U>
where
U: crate::UninitThis<Target = Self>,
{
private::Partial(this)
}
}
pub trait State: ThisPtr<Target = super::super::Foo> {
type Flags;
type Inited;
unsafe fn assume_init(self) -> Self::Inited;
}
impl<U: UninitThis<Target = super::super::Foo>> State for U {
type Flags = U0;
type Inited = U::Inited;
unsafe fn assume_init(self) -> Self::Inited {
unsafe { U::assume_init(self) }
}
}
impl<N> State for foo<N>
where
N: State,
N::Flags: BitOr<U1>,
{
type Flags = Or<N::Flags, U1>;
type Inited = N::Inited;
unsafe fn assume_init(self) -> Self::Inited {
unsafe {
let this = ManuallyDrop::new(self);
core::ptr::read(&this.0).assume_init()
}
}
}
impl<N> State for bar<N>
where
N: State,
N::Flags: BitOr<Shleft<U1, U1>>,
{
type Flags = Or<N::Flags, U2>;
type Inited = N::Inited;
unsafe fn assume_init(self) -> Self::Inited {
unsafe {
let this = ManuallyDrop::new(self);
core::ptr::read(&this.0).assume_init()
}
}
}
impl<N> Partial<N>
where
N: ThisPtr<Target = super::super::Foo> + State,
N::Flags: BitAnd<U1, Output = U0>,
{
pub unsafe fn assume_init_foo(self) -> Partial<foo<N>> {
Partial(foo(self.0))
}
pub fn foo(mut self, value: i32) -> Partial<foo<N>> {
unsafe { core::ptr::write(&mut (*self.0.this_mut().as_mut_ptr()).foo, value) };
Partial(foo(self.0))
}
}
impl<N> Partial<N>
where
N: ThisPtr<Target = super::super::Foo> + State,
N::Flags: BitAnd<U2, Output = U0>,
{
pub unsafe fn assume_init_bar(self) -> Partial<bar<N>> {
Partial(bar(self.0))
}
pub fn bar(mut self, value: f32) -> Partial<bar<N>> {
unsafe { core::ptr::write(&mut (*self.0.this_mut().as_mut_ptr()).bar, value) };
Partial(bar(self.0))
}
}
impl<N> Partial<N>
where
N: ThisPtr<Target = super::super::Foo> + State,
N::Flags: BitAnd<U1, Output = U1>,
{
pub fn set_foo(&mut self, value: i32) {
*self.get_foo_mut() = value;
}
pub fn get_foo(&self) -> &i32 {
unsafe { &(*self.0.this().as_ptr()).foo }
}
pub fn get_foo_mut(&mut self) -> &mut i32 {
unsafe { &mut (*self.0.this_mut().as_mut_ptr()).foo }
}
}
impl<N> Partial<N>
where
N: ThisPtr<Target = super::super::Foo> + State,
N::Flags: BitAnd<U2, Output = U2>,
{
pub fn set_bar(&mut self, value: f32) {
*self.get_bar_mut() = value;
}
pub fn get_bar(&self) -> &f32 {
unsafe { &(*self.0.this().as_ptr()).bar }
}
pub fn get_bar_mut(&mut self) -> &mut f32 {
unsafe { &mut (*self.0.this_mut().as_mut_ptr()).bar }
}
}
impl<N> Partial<N>
where
N: State<Flags = U3>,
{
pub fn done(self) -> N::Inited {
unsafe { self.0.assume_init() }
}
}
}
}
#[test]
fn test1() {
let a = Foo::partial(Box::new_uninit());
let mut a = a.foo(1);
a.set_foo(123);
let a = a.bar(456.0).done();
assert_eq!(a.foo, 123);
assert_eq!(a.bar, 456.0)
}
}
#[cfg(test)]
pub mod test_macro {
use super::*;
#[partial]
pub struct Foo {
pub foo: i32,
pub bar: f32,
}
#[test]
fn macro_generates_partial() {
let a = Foo::partial(Box::new_uninit());
let mut a = a.foo(1);
a.set_foo(123);
let a = a.bar(456.0).done();
assert_eq!(a.foo, 123);
assert_eq!(a.bar, 456.0);
}
}