// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 //! Unsafe module that is only enabled when the `std` feature is off. //! It re-implements the thread_local macro with statics #![allow(unsafe_code)] #[macro_export] macro_rules! SLINT__thread_local_inner { ($(#[$($meta:tt)*])* $vis:vis $ident:ident $ty:ty $block:block) => { $(#[$($meta)*])* $vis static $ident: crate::unsafe_single_threaded::FakeThreadStorage<$ty> = { fn init() -> $ty $block crate::unsafe_single_threaded::FakeThreadStorage::new(init) }; }; } #[macro_export] macro_rules! thread_local_ { // Taken from stdlib! // empty (base case for the recursion) () => {}; ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => ( $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t $init); $crate::thread_local!($($rest)*); ); ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => ( $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t $init); ); // process multiple declarations ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t { $init }); $crate::thread_local!($($rest)*); ); // handle a single declaration ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t { $init }); ); } pub struct FakeThreadStorage T>(once_cell::unsync::OnceCell, F); impl FakeThreadStorage { pub const fn new(f: F) -> Self { Self(once_cell::unsync::OnceCell::new(), f) } } impl FakeThreadStorage { pub fn with(&self, f: impl FnOnce(&T) -> R) -> R { f(self.0.get_or_init(self.1)) } pub fn try_with(&self, f: impl FnOnce(&T) -> R) -> Result { Ok(f(self.0.get().ok_or(())?)) } } // Safety: the unsafe_single_threaded feature means we will only be called from a single thread unsafe impl Send for FakeThreadStorage {} unsafe impl Sync for FakeThreadStorage {} pub use thread_local_ as thread_local; pub struct OnceCell(once_cell::unsync::OnceCell); impl OnceCell { pub const fn new() -> Self { Self(once_cell::unsync::OnceCell::new()) } pub fn get(&self) -> Option<&T> { self.0.get() } pub fn set(&self, value: T) -> Result<(), T> { self.0.set(value) } } // Safety: the unsafe_single_threaded feature means we will only be called from a single thread unsafe impl Send for OnceCell {} unsafe impl Sync for OnceCell {}