ztimer 0.1.2

A block-based, non-circular double-linked list implementation for Rust.
Documentation
// Copyright 2024 Lorby Bi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// `srcell` stands for Synchronized (unsafe) Reference Count (Ref)Cell.
// It is a wrapper around `Rc<RefCell>`, intended for use within mutex-protected structures.
// This wrapper is specifically designed for scenarios involving reference counting within mutexes.
// The standard `std::rc::Rc` type does not implement the `Sync` or `Send` traits, making it unsafe for multi-threaded access.
// In the `ztimer` structure, the TPL/Scheduler is protected by a mutex, ensuring it is not accessed across threads without protection.
// For performance reasons, `SyncUnsafeRcRefCell` is used instead of `Arc<Mutex<T>>`.
// `SyncUnsafeRcRefCell` should only be used inside mutex-protected structures and should not be cloned or accessed outside the mutex.
// This type is meant for internal use within the `ztimer` crate and should not be exported or used in other crates.

use anyhow::Result as AnyResult;
use std::cell::{Ref, RefCell, RefMut};
use std::rc::{Rc, Weak};

#[derive(Debug)]
pub(in super::super) struct SyncUnsafeRcRefCell<T>(pub(super) Rc<RefCell<T>>);


impl<T> SyncUnsafeRcRefCell<T> {
    pub(in super::super) fn new(t: T) -> Self {
        SyncUnsafeRcRefCell(Rc::new(RefCell::new(t)))
    }
    pub(in super::super) fn new_cyclic<F>(f: F) -> Self
    where
        F: FnOnce(SyncUnsafeWeakRefCell<T>) -> T,
    {
        let r =Rc::new_cyclic(|d: &Weak<RefCell<T>>| {
            RefCell::new(f(SyncUnsafeWeakRefCell(Weak::clone(d))))
        });
        SyncUnsafeRcRefCell(r)
    }
    pub(in super::super) fn unsafe_downgrade(&self) -> SyncUnsafeWeakRefCell<T> {
        SyncUnsafeWeakRefCell(Rc::downgrade(&self.0))
    }
    pub(in super::super) fn unsafe_try_borrow_mut(&self) -> AnyResult<RefMut<'_, T>> {
        self.0.try_borrow_mut().or_else(|e| Err(e.into()))
    }
    pub(in super::super) fn unsafe_try_borrow(&self) -> AnyResult<Ref<'_, T>> {
        self.0.try_borrow().or_else(|e| Err(e.into()))
    }
    pub(in super::super) fn unsafe_clone(&self) -> Self {
        SyncUnsafeRcRefCell(self.0.clone())
    }
}

unsafe impl<T> Send for SyncUnsafeRcRefCell<T> {}

#[derive(Debug)]
pub(in super::super) struct SyncUnsafeWeakRefCell<T>(pub(super) Weak<RefCell<T>>);
impl<T> SyncUnsafeWeakRefCell<T> {
    pub(in super::super) fn unsafe_upgrade(&self) -> Option<SyncUnsafeRcRefCell<T>> {
        self.0.upgrade().map(|r| SyncUnsafeRcRefCell(r))
    }
    pub(in super::super) fn unsafe_clone(&self) -> Self {
        SyncUnsafeWeakRefCell(self.0.clone())
    }
}

unsafe impl<T> Send for SyncUnsafeWeakRefCell<T> {}