|
| 1 | +//! A design based around the `allow::Ref` type, which is a type that can point |
| 2 | +//! to both 'static and stack-based buffers. `allow::Ref` itself is type (and |
| 3 | +//! lifetime)-erased to avoid monomorphization bloat in APIs. However, it is |
| 4 | +//! limited to only RO Allows or only RW Allows (because only allow::Ref<Ro> can |
| 5 | +//! be created from a `&'static [u8]`). |
| 6 | +
|
| 7 | +pub type ErrorCode = u32; |
| 8 | + |
| 9 | +pub mod allow { |
| 10 | + use core::ptr::null_mut; |
| 11 | + use crate::*; |
| 12 | + |
| 13 | + /// A reference to something that can be shared with the kernel via the |
| 14 | + /// Read-Only Allow system call (and if P is Rw, read-write Allow). |
| 15 | + pub struct Ref<P: Permissions, T: Allowable> { |
| 16 | + // The lifetime is erased to 'static here. There is no correct lifetime to |
| 17 | + // write when an AllowRef is embedded inside a Buffer. |
| 18 | + buffer: P::BufRef<'static, T>, |
| 19 | + // APIs need to be able to retrieve mutable references to the buffer |
| 20 | + // (for RW Allow), which requires that they have an exclusive reference |
| 21 | + // to the Ref. However, giving an &mut reference to the Ref would allow |
| 22 | + // the buffer to replace the Ref and forget it, which would prevent the |
| 23 | + // unallow from occurring before the buffer is dropped. To prevent that, |
| 24 | + // we pin the Ref as well. |
| 25 | + _pinned: PhantomPinned, |
| 26 | + share_info: Option<ShareInfo>, |
| 27 | + } |
| 28 | + |
| 29 | + impl<P: Permissions, T: Allowable> Ref<P, T> { |
| 30 | + fn unshare_if_shared(self: Pin<&mut Self>) { |
| 31 | + let this = unsafe { Pin::into_inner_unchecked(self) }; |
| 32 | + let Some(ref info) = this.share_info else { return }; |
| 33 | + unsafe { |
| 34 | + dynamic_allow(info.driver_num, info.buffer_num, null_mut(), 0, info.allow_type); |
| 35 | + } |
| 36 | + this.share_info = None; |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + struct ShareInfo { |
| 41 | + allow_type: DynamicType, |
| 42 | + driver_num: u32, |
| 43 | + buffer_num: u32, |
| 44 | + } |
| 45 | + |
| 46 | + /// Trait representing an allowable type. |
| 47 | + pub trait Allowable: FromBytes + IntoBytes + 'static {} |
| 48 | + impl<T: FromBytes + IntoBytes + ?Sized + 'static> Allowable for T {} |
| 49 | + |
| 50 | + /// A type that represents whether a `Ref` has write access to a buffer. |
| 51 | + pub trait Permissions: sealed::Sealed { |
| 52 | + type BufRef<'b, T: Allowable>; |
| 53 | + // Only exists within the context of this design exploration; would not |
| 54 | + // exist in libtock-rs (because Permissions replaces StaticType |
| 55 | + // entirely). |
| 56 | + type Static: StaticType; |
| 57 | + } |
| 58 | + |
| 59 | + // Permissions implementations. |
| 60 | + pub enum Ro {} |
| 61 | + impl sealed::Sealed for Ro {} |
| 62 | + impl Permissions for Ro { |
| 63 | + type BufRef<'b, T: Allowable> = &'b T; |
| 64 | + type Static = StaticRo; |
| 65 | + } |
| 66 | + pub enum Rw {} |
| 67 | + impl sealed::Sealed for Rw {} |
| 68 | + impl Permissions for Rw { |
| 69 | + type BufRef<'b, T: Allowable> = &'b mut T; |
| 70 | + type Static = StaticRw; |
| 71 | + } |
| 72 | + |
| 73 | + mod sealed { |
| 74 | + pub trait Sealed {} |
| 75 | + } |
| 76 | +} |
0 commit comments