diff --git a/examples/field_type.rs b/examples/field_type.rs new file mode 100644 index 0000000..a1a7775 --- /dev/null +++ b/examples/field_type.rs @@ -0,0 +1,132 @@ +use field_projection::{ + compat::HasFields, + field_of, + marker::{Field, UnalignedField}, +}; + +use core::ptr::null_mut; +use std::sync::Arc; + +/// An intrusive struct to link all queued work together. +pub struct Work { + state: usize, + func: Option, + next: *mut Work, +} + +pub trait WorkItem { + fn run(&self); +} + +impl WorkItem for Foo { + fn run(&self) { + println!("hello work"); + } +} + +impl WorkItem for Foo { + fn run(&self) { + println!("hello work2"); + } +} + +fn bridge>(ptr: *mut Work) +where + F::Base: WorkItem + Sized, +{ + let ptr = unsafe { ptr.byte_sub(F::OFFSET) }.cast::(); + + unsafe { &*ptr }.run(); +} + +impl Work { + /// TODO: this should return PinInit. + /// + /// # Safety + /// + /// Callers must guarantee the `Work` is the exact field described by `F`. + pub const unsafe fn new>() -> Self + where + F::Base: WorkItem + Sized, + { + Self { + state: 0, + func: Some(bridge::), + next: null_mut(), + } + } +} + +#[derive(HasFields)] +pub struct Foo { + a: i32, + b: i32, + work: Work, + work2: Work, +} + +impl Foo { + pub fn new_arc(a: i32, b: i32) -> Arc { + Arc::new(Self { + a, + b, + // SAFETY: `work` is Foo::work. + work: unsafe { Work::new::() }, + // SAFETY: `work2` is Foo::work2. + work2: unsafe { Work::new::() }, + }) + } +} + +pub trait WorkItemPointer>: Sized { + // Simulates RawWorkItem + fn into_work(self) -> *mut Work; + + fn c_run(ptr: *mut Work); +} + +impl> WorkItemPointer for Arc +where + T: WorkItem, +{ + fn into_work(self) -> *mut Work { + let ptr = Arc::into_raw(self); + unsafe { ptr.byte_add(F::OFFSET).cast_mut().cast() } + } + + fn c_run(ptr: *mut Work) { + let ptr = unsafe { ptr.byte_sub(F::OFFSET).cast::() }; + + let arc = unsafe { Arc::from_raw(ptr) }; + + arc.run(); + } +} + +/// # Safety +/// +/// `work` must point to a valid pointer of `Work`. +unsafe fn c_run_work(work: *mut Work) { + if let Some(func) = unsafe { (*work).func } { + func(work) + } +} + +pub fn queue_work, T: WorkItem, P: WorkItemPointer>(p: P) { + // Simulate queue work and run + // + // TODO: simulate linking work and execute them all together. + let ptr = p.into_work(); + + // SAFETY: `ptr` is a valid pointer of `Work`. + unsafe { c_run_work(ptr) }; +} + +#[test] +fn main() { + let foo = Foo::new_arc(12, 42); + let foo2 = Foo::new_arc(12, 42); + + queue_work::(foo); + queue_work::(foo2); +}