rt 0.19.1

A real-time operating system capable of full preemption
Documentation
use core::{
    cell::UnsafeCell,
    panic::{RefUnwindSafe, UnwindSafe},
};

use crate::{
    bindings::{rt_barrier, rt_barrier_wait, rt_mutex},
    list::list_init,
    ptr_macros::{ptr_to_field, ptr_to_field_mut},
    sync::condvar::c_cond_init,
};

#[repr(transparent)]
pub struct Barrier {
    barrier: UnsafeCell<rt_barrier>,
}

unsafe impl Send for Barrier {}
unsafe impl Sync for Barrier {}
impl UnwindSafe for Barrier {}
impl RefUnwindSafe for Barrier {}

pub struct BarrierWaitResult(bool);

impl Barrier {
    /// Initialize a new `Barrier` with the given count.
    ///
    /// # Safety
    ///
    /// This must be called with a pointer to a `static` `Barrier` and be used to initialize that
    /// same `Barrier`. Users should use the `rt::sync::barrier!` macro to create a `Barrier`
    /// rather than call `Barrier::init` directly.
    #[must_use]
    pub const unsafe fn init(this: *const Self, count: u32) -> Barrier {
        let barrier = UnsafeCell::raw_get(ptr_to_field!(this, barrier));
        Barrier {
            barrier: UnsafeCell::new(rt_barrier {
                mutex: rt_mutex {
                    holder: 0,
                    wait_list: list_init(ptr_to_field_mut!(barrier, mutex, wait_list)),
                    list: list_init(ptr_to_field_mut!(barrier, mutex, list)),
                    level: -1,
                },
                cond: c_cond_init(ptr_to_field_mut!(barrier, cond)),
                level: 0,
                threshold: count,
                generation: 0,
            }),
        }
    }

    /// Blocks the current task until `n` tasks have called `wait`. One task among the `n` will be
    /// designated as the leader, and `wait().is_leader()` will return `true` for that task only.
    #[inline]
    pub fn wait(&self) -> BarrierWaitResult {
        BarrierWaitResult(unsafe { rt_barrier_wait(self.barrier.get()) })
    }
}

impl BarrierWaitResult {
    #[must_use]
    pub fn is_leader(&self) -> bool {
        self.0
    }
}

#[macro_export]
macro_rules! barrier {
    ($name: ident, $count: expr) => {
        static $name: $crate::sync::Barrier = {
            let ptr = &raw const $name;
            let count = $count;
            unsafe { $crate::sync::Barrier::init(ptr, count) }
        };
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn fast_path() {
        barrier!(BARRIER, 1);
        assert!(BARRIER.wait().is_leader());
    }
}