rta-for-fps-lib 0.2.0

An Implementation of the paper 'Response Time Analysis for Fixed Priority Servers' by Hamann et al
Documentation
//! Module for the `Peeker` and `PeekRef` implementation and definition

use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;

/// Smart Pointer to a Peek Element
/// allows viewing, modifying and taking the Peek Element
#[derive(Debug)]
pub struct PeekRef<'a, I> {
    /// The reference to the nested options containing the Peek Element
    #[allow(clippy::option_option)]
    container: NonNull<Option<Option<I>>>,
    /// The reference to the element contained in the above options
    inner: NonNull<I>,
    /// make sure we have the correct variance and
    /// the only one with access to the original reference
    /// while we are alive
    mut_ref: PhantomData<&'a mut I>,
}

impl<'a, I> Deref for PeekRef<'a, I> {
    type Target = I;

    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

impl<'a, I> DerefMut for PeekRef<'a, I> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.as_mut()
    }
}

impl<'a, I> PeekRef<'a, I> {
    /// Create a new `PeekRef` for the nested Options
    #[allow(clippy::option_option)]
    pub fn new(option: &'a mut Option<Option<I>>) -> Option<PeekRef<'a, I>> {
        let option_ref = NonNull::from(&*option);
        option
            .as_mut()
            .and_then(core::option::Option::as_mut)
            .map(|inner| PeekRef {
                container: option_ref,
                inner: NonNull::from(inner),
                mut_ref: PhantomData::<&'a mut I>,
            })
    }

    /// Consume the `PeekRef` and get the peek element
    #[allow(clippy::must_use_candidate)]
    pub fn take(mut self) -> I {
        unsafe {
            // Safety:
            // This type is constructed from mutable references to Options that contain the Some variant
            // This types interface makes sure that the inner pointer stays valid until this value is
            // dropped or take is called
            //
            // As we consume self it is safe to invalidate inner as we don't use it here
            // and drop our self at the end of the function
            self.container.as_mut()
        }
        .take()
        .flatten()
        .expect("Constructed only for Some variant containing Some variant")
    }

    /// Get a mutable reference to the peek element
    fn as_mut(&mut self) -> &mut I {
        unsafe {
            // Safety:
            // This type is constructed from mutable references to Options that contain the Some variant
            // This types interface makes sure that the inner pointer stays valid until this value is
            // dropped or take is called
            //
            // As we have a mutable reference to self we can't have given out another reference
            // currently
            self.inner.as_mut()
        }
    }
    /// Get an immutable reference to the peek element
    fn as_ref(&self) -> &I {
        unsafe {
            // Safety:
            // This type is constructed from mutable references to Options that contain the Some variant
            // This types interface makes sure that the inner pointer stays valid until this value is
            // dropped or take is called
            //
            // As we have a reference to self we can't have given out a mutable reference
            // currently
            self.inner.as_ref()
        }
    }
}

/// A version of the standard libraries [`Peekable`](core::iter::Peekable) that lets one restore/replace/clear the peek element
#[derive(Debug, Clone)]
pub struct Peeker<I, IT> {
    /// The iterator we are peeking into
    iter: I,
    /// If Some contains the peeked at value
    /// which may be a None
    /// Otherwise we have not peeked since the last next call
    /// or the value was taken via a PeekRef
    #[allow(clippy::option_option)]
    peek_window: Option<Option<IT>>,
}

impl<I, IT> Peeker<I, IT>
where
    I: Iterator<Item = IT>,
{
    /// Create a new `Peeker`
    pub fn new(inner: I) -> Self {
        Self {
            iter: inner,
            peek_window: None,
        }
    }

    /// Take a peek at the element that will be returned from the next next call
    pub fn peek(&mut self) -> Option<&IT> {
        self.peek_ref_mut().as_ref()
    }

    /// Take a mutable peek at the element that will be returned from the next next call
    /// Changing the value behind the reference will change the next element
    pub fn peek_mut(&mut self) -> Option<&mut IT> {
        self.peek_ref_mut().as_mut()
    }

    /// Peek into the iterator if not done already and get a `PeekRef`
    /// to the peeked value if it was Some
    pub fn peek_ref(&mut self) -> Option<PeekRef<'_, IT>> {
        self.peek_ref_mut();
        PeekRef::new(&mut self.peek_window)
    }

    /// Make sure the peek slot is filled and return a mutable reference to the inner option
    fn peek_ref_mut(&mut self) -> &mut Option<IT> {
        let iter = &mut self.iter;
        self.peek_window.get_or_insert_with(|| iter.next())
    }

    /// Set a peek window if there currently is none
    ///
    /// # Panics
    /// If there is a window held as peek
    pub fn restore_peek(&mut self, window: IT) {
        if self.peek_window.take().flatten().is_none() {
            self.peek_window = Some(Some(window))
        } else {
            panic!("Restoring over existing peek window!")
        }
    }
}

impl<I, IT> Iterator for Peeker<I, IT>
where
    I: Iterator<Item = IT>,
{
    type Item = IT;

    fn next(&mut self) -> Option<Self::Item> {
        self.peek_window.take().unwrap_or_else(|| self.iter.next())
    }
}