maybe_sync/
lib.rs

1//! This crates helps creating flexible libraries that may work in either
2//! multithreaded and singlethreaded environments.
3//!
4//! [![crates](https://img.shields.io/crates/v/maybe-sync.svg?label=maybe-sync)](https://crates.io/crates/maybe-sync)
5//! [![docs](https://docs.rs/maybe-sync/badge.svg)](https://docs.rs/maybe-sync)
6//! [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)
7//! [![License](https://img.shields.io/badge/license-APACHE-blue.svg)](LICENSE-APACHE)
8//!
9//! # Why it exists?
10//!
11//! Creating library that works in either desktop/server or web-browser environment
12//! could be tough.
13//!
14//! In desktop/server environments crates tend to be usable with multiple threads
15//! and add [`Send`] and [`Sync`] trait bounds where needed.
16//! In the same time [`web-sys`] - a de facto standard crate to use browser API -
17//! provides programmer with `!Send + !Sync` types that cannot be used when [`Send`]
18//! or [`Sync`] bounds are placed on the API calls.
19//!
20//! For example asset loading crate [`goods`] uses generic executors to drive
21//! loading process.
22//! Some executors work with sendable futures only: [`tokio`],
23//! some requre sendable future to run them on multiple threads:
24//! [`async-std`], [`actix-rt`],
25//! Others work with any futures in single thread: [`wasm_bindgen_futures::spawn_local`]
26//!
27//! In [`goods`] one of the basic data sources for web - [`FetchSource`] - uses
28//! browser's Fetch API to retreive data from web and produces non-sendable future.
29//!
30//! That's why [`goods::Spawn::spawn`] takes [`maybe_sync::BoxFuture`] that is
31//! a sendable boxed future when "sync" feature is enabled,
32//! allowing using multithreaded future executors.
33//! And without "sync" feature [`maybe_sync::BoxFuture`] is
34//! a non-sendable boxed future and only then [`FetchSource`] exists.
35//!
36//! Similar story with ECS crates.
37//! Most of them require that components are [`Send`] + [`Sync`]
38//! so systems can access them from any thread.
39//! This makes it impossible to have types from [`web-sys`] in components.
40//!
41//! Some small application may desire to turn off "sync" feature in their
42//! dependencies as they are singlethreaded and would rather not pay for what
43//! they don't use.
44//!
45//! # [`MaybeSend`] and [`MaybeSync`]
46//!
47//! Marker traits [`MaybeSend`] and [`MaybeSync`] can be used in place of
48//! [`Send`] and [`Sync`] traits in where clauses and bounds.
49//!
50//! When "sync" feature is enabled then [`MaybeSend`] is actually reexported [`Send`]
51//! and [`MaybeSync`] is reexported [`Sync`] trait.
52//! Thus allowing types with those bounds to be sent or shared across threads.
53//!
54//! When "sync" feature is not enabled then [`MaybeSend`] and [`MaybeSync`] are empty
55//! traits implemented for all types and when used as bounds permit types that
56//! does not satisfy [`Send`] or [`Sync`] bounds.
57//!
58//! This makes it impossible to forget enable "sync" feature and accidentally send
59//! `!Send` value to another thread.
60//! Function that uncodintionally send value to another thread
61//! should not use [`MaybeSend`] bound, but an actual [`Send`].
62//!
63//! # BoxFuture
64//!
65//! Type alias for boxed future. Sendable if "sync" feature is enabled.
66//! It is designed to be used as return type from trait functions
67//! where trait implementations that produce non-sendable futures
68//! exist only when "sync" feature is not enabled.
69//! It can be used as function argument type when [`MaybeSend`] bound is placed.
70//!
71//! # Rc
72//!
73//! Type alias to [`alloc::rc::Rc`] when "sync" feature is not enabled, or
74//! [`alloc::sync::Arc`] when "sync" feature is enabled. Serves for optimization
75//! purposes for crates that already use [`maybe-sync`] crate.
76//!
77//! # Mutex
78//!
79//! Type alias to [`parking_lot::Mutex`] when "sync" feature is enabled, or
80//! thin wrapper arond [`core::cell::RefCell`] otherwise. Serves for optimization
81//! purposes for crates that already use [`maybe-sync`] crate.
82//!
83//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
84//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
85//! [`web-sys`]: https://docs.rs/web-sys
86//! [`goods`]: https://docs.rs/goods
87//! [`tokio`]: https://docs.rs/tokio
88//! [`async-std`]: https://docs.rs/async-std
89//! [`actix-rt`]: https://docs.rs/actix-rt
90//! [`FetchSource`]: https://docs.rs/goods/0.5/wasm32-unknown-unknown/goods/struct.FetchSource.html
91//! [`wasm_bindgen_futures::spawn_local`]: https://docs.rs/wasm-bindgen-futures/0.4/wasm_bindgen_futures/fn.spawn_local.html
92//! [`goods::Spawn::spawn`]: https://docs.rs/goods/0.5/goods/trait.Spawn.html#tymethod.spawn
93//! [`maybe_sync::BoxFuture`]: ./type.BoxFuture.html
94//! [`MaybeSend`]: ./trait.MaybeSend.html
95//! [`MaybeSync`]: ./trait.MaybeSync.html
96//! [`alloc::rc::Rc`]: https://doc.rust-lang.org/alloc/rc/struct.Rc.html
97//! [`alloc::sync::Arc`]: https://doc.rust-lang.org/alloc/sync/struct.Arc.html
98//! [`maybe-sync`]: ./index.html
99//! [`parking_lot::Mutex`]: https://docs.rs/parking_lot/0.10/parking_lot/type.Mutex.html
100//! [`core::cell::RefCell`]: https://doc.rust-lang.org/core/cell/struct.RefCell.html
101
102#![no_std]
103#![cfg_attr(all(doc, feature = "unstable-doc"), feature(doc_cfg))]
104
105#[cfg(feature = "alloc")]
106extern crate alloc;
107
108#[cfg(feature = "sync")]
109mod sync {
110    #[cfg(feature = "alloc")]
111    use core::{future::Future, pin::Pin};
112
113    /// Reexports of the actual marker traits from core.
114    pub use core::marker::{Send as MaybeSend, Sync as MaybeSync};
115
116    /// An owned dynamically typed [`Future`] for use at return position in cases
117    /// when type is opaque and existential type cannot be used,
118    /// or when multiple types can be returned.
119    ///
120    /// A type alias equal to `futures::future::BoxFuture`
121    /// when "sync" feature is enabled.\
122    /// A type alias equal to `futures::future::LocalBoxFuture`
123    /// when "sync" feature is not enabled.
124    #[cfg(feature = "alloc")]
125    #[cfg_attr(all(doc, feature = "unstable-doc"), doc(cfg(feature = "alloc")))]
126    pub type BoxFuture<'a, T> = Pin<alloc::boxed::Box<dyn Future<Output = T> + Send + 'a>>;
127
128    /// A pointer type which can be safely shared between threads
129    /// when "sync" feature is enabled.\
130    /// A pointer type which can be shared, but only within single thread
131    /// where it was created when "sync" feature is not enabled.
132    ///
133    /// # Example
134    ///
135    /// ```
136    /// # use {maybe_sync::{MaybeSend, Rc}, std::fmt::Debug};
137    ///
138    /// fn maybe_sends<T: MaybeSend + Debug + 'static>(val: T) {
139    ///   #[cfg(feature = "sync")]
140    ///   {
141    ///     // If this code is compiled then `MaybeSend` is alias to `std::marker::Send`.
142    ///     std::thread::spawn(move || { println!("{:?}", val) });
143    ///   }
144    /// }
145    ///
146    /// // Unlike `std::rc::Rc` this `maybe_sync::Rc` always satisfies `MaybeSend` bound.
147    /// maybe_sends(Rc::new(42));
148    /// ```
149    #[cfg(feature = "alloc")]
150    #[cfg_attr(all(doc, feature = "unstable-doc"), doc(cfg(feature = "alloc")))]
151    pub type Rc<T> = alloc::sync::Arc<T>;
152
153    /// Mutex implementation to use in conjunction with `MaybeSync` bound.
154    ///
155    /// A type alias to `parking_lot::Mutex` when "sync" feature is enabled.\
156    /// A wrapper type around `std::cell::RefCell` when "sync" feature is not enabled.
157    ///
158    /// # Example
159    ///
160    /// ```
161    /// # use {maybe_sync::{MaybeSend, Mutex}, std::{fmt::Debug, sync::Arc}};
162    ///
163    /// fn maybe_sends<T: MaybeSend + Debug + 'static>(val: Arc<Mutex<T>>) {
164    ///   #[cfg(feature = "sync")]
165    ///   {
166    ///     // If this code is compiled then `MaybeSend` is alias to `std::marker::Send`,
167    ///     // and `Mutex` is `parking_lot::Mutex`.
168    ///     std::thread::spawn(move || { println!("{:?}", *val.lock()) });
169    ///   }
170    /// }
171    ///
172    /// // `maybe_sync::Mutex<T>` would always satisfy `MaybeSync` and `MaybeSend`
173    /// // bounds when `T: MaybeSend`,
174    /// // even if feature "sync" is enabeld.
175    /// maybe_sends(Arc::new(Mutex::new(42)));
176    /// ```
177    pub type Mutex<T> = parking_lot::Mutex<T>;
178
179    /// A boolean type which can be safely shared between threads
180    /// when "sync" feature is enabled.\
181    /// A boolean type with non-threadsafe interior mutability
182    /// when "sync" feature is not enabled.
183    ///
184    /// This type has the same in-memory representation as a bool.
185    pub type AtomicBool = core::sync::atomic::AtomicBool;
186
187    /// A integer type which can be safely shared between threads
188    /// when "sync" feature is enabled.\
189    /// A integer type with non-threadsafe interior mutability
190    /// when "sync" feature is not enabled.
191    ///
192    /// This type has the same in-memory representation as a i8.
193    pub type AtomicI8 = core::sync::atomic::AtomicI8;
194
195    /// A integer type which can be safely shared between threads
196    /// when "sync" feature is enabled.\
197    /// A integer type with non-threadsafe interior mutability
198    /// when "sync" feature is not enabled.
199    ///
200    /// This type has the same in-memory representation as a i16.
201    pub type AtomicI16 = core::sync::atomic::AtomicI16;
202
203    /// A integer type which can be safely shared between threads
204    /// when "sync" feature is enabled.\
205    /// A integer type with non-threadsafe interior mutability
206    /// when "sync" feature is not enabled.
207    ///
208    /// This type has the same in-memory representation as a i32.
209    pub type AtomicI32 = core::sync::atomic::AtomicI32;
210
211    /// A integer type which can be safely shared between threads
212    /// when "sync" feature is enabled.\
213    /// A integer type with non-threadsafe interior mutability
214    /// when "sync" feature is not enabled.
215    ///
216    /// This type has the same in-memory representation as a isize.
217    pub type AtomicIsize = core::sync::atomic::AtomicIsize;
218
219    /// A integer type which can be safely shared between threads
220    /// when "sync" feature is enabled.\
221    /// A integer type with non-threadsafe interior mutability
222    /// when "sync" feature is not enabled.
223    ///
224    /// This type has the same in-memory representation as a i8.
225    pub type AtomicU8 = core::sync::atomic::AtomicU8;
226
227    /// A integer type which can be safely shared between threads
228    /// when "sync" feature is enabled.\
229    /// A integer type with non-threadsafe interior mutability
230    /// when "sync" feature is not enabled.
231    ///
232    /// This type has the same in-memory representation as a i16.
233    pub type AtomicU16 = core::sync::atomic::AtomicU16;
234
235    /// A integer type which can be safely shared between threads
236    /// when "sync" feature is enabled.\
237    /// A integer type with non-threadsafe interior mutability
238    /// when "sync" feature is not enabled.
239    ///
240    /// This type has the same in-memory representation as a i32.
241    pub type AtomicU32 = core::sync::atomic::AtomicU32;
242
243    /// A integer type which can be safely shared between threads
244    /// when "sync" feature is enabled.\
245    /// A integer type with non-threadsafe interior mutability
246    /// when "sync" feature is not enabled.
247    ///
248    /// This type has the same in-memory representation as a isize.
249    pub type AtomicUsize = core::sync::atomic::AtomicUsize;
250
251    /// A raw pointer type which can be safely shared between threads
252    /// when "sync" feature is enabled.\
253    /// A raw pointer type with non-threadsafe interior mutability
254    /// when "sync" feature is not enabled.
255    ///
256    /// This type has the same in-memory representation as a isize.
257    pub type AtomicPtr<T> = core::sync::atomic::AtomicPtr<T>;
258}
259
260#[cfg(not(feature = "sync"))]
261mod unsync {
262    use core::cell::{RefCell, RefMut};
263
264    #[cfg(feature = "alloc")]
265    use core::{future::Future, pin::Pin};
266
267    /// Marker trait that can represent nothing if feature "sync" is not enabled.
268    /// Or be reexport of `std::marker::Send` if "sync" feature is enabled.
269    ///
270    /// It is intended to be used as trait bound where `std::marker::Send` bound
271    /// is required only when application is compiled for multithreaded environment.\
272    /// If "sync" feature is not enabled then this trait bound will *NOT* allow
273    /// value to cross thread boundary or be used where sendable value is expected.
274    ///
275    /// # Examples
276    ///
277    /// ```
278    /// # use {maybe_sync::MaybeSend, std::{fmt::Debug, rc::Rc}};
279    ///
280    /// fn maybe_sends<T: MaybeSend + Debug + 'static>(val: T) {
281    ///   #[cfg(feature = "sync")]
282    ///   {
283    ///     // If this code is compiled then `MaybeSend` is alias to `std::marker::Send`.
284    ///     std::thread::spawn(move || { println!("{:?}", val) });
285    ///   }
286    /// }
287    ///
288    /// #[cfg(not(feature = "sync"))]
289    /// {
290    ///   // If this code is compiled then `MaybeSend` dummy markerd implemented for all types.
291    ///   maybe_sends(Rc::new(42));
292    /// }
293    /// ```
294    pub trait MaybeSend {}
295
296    /// All values are maybe sendable.
297    impl<T> MaybeSend for T where T: ?Sized {}
298
299    /// Marker trait that can represent nothing if feature "sync" is not enabled.
300    /// Or be reexport of `std::marker::Sync` if "sync" feature is enabled.
301    ///
302    /// It is intended to be used as trait bound where `std::marker::Sync` bound
303    /// is required only when application is compiled for multithreaded environment.\
304    /// If "sync" feature is not enabled then this trait bound will *NOT* allow
305    /// reference to the value to cross thread boundary or be used where sync
306    /// value is expected.
307    ///
308    /// # Examples
309    ///
310    /// ```
311    /// # use {maybe_sync::MaybeSync, std::{sync::Arc, fmt::Debug, cell::Cell}};
312    ///
313    /// fn maybe_shares<T: MaybeSync + Debug + 'static>(val: Arc<T>) {
314    ///   #[cfg(feature = "sync")]
315    ///   {
316    ///     // If this code is compiled then `MaybeSync` is alias to `std::marker::Sync`.
317    ///     std::thread::spawn(move || { println!("{:?}", val) });
318    ///   }
319    /// }
320    ///
321    /// #[cfg(not(feature = "sync"))]
322    /// {
323    ///   // If this code is compiled then `MaybeSync` dummy markerd implemented for all types.
324    ///   maybe_shares(Arc::new(Cell::new(42)));
325    /// }
326    /// ```
327    pub trait MaybeSync {}
328
329    /// All values are maybe sync.
330    impl<T> MaybeSync for T where T: ?Sized {}
331
332    /// An owned dynamically typed [`Future`] for use at return position in cases
333    /// when type is opaque and existential type cannot be used,
334    /// or when multiple types can be returned.
335    ///
336    /// A type alias equal to `futures::future::BoxFuture`
337    /// when "sync" feature is enabled.\
338    /// A type alias equal to `futures::future::LocalBoxFuture`
339    /// when "sync" feature is not enabled.
340    #[cfg(feature = "alloc")]
341    #[cfg_attr(all(doc, feature = "unstable-doc"), doc(cfg(feature = "alloc")))]
342    pub type BoxFuture<'a, T> = Pin<alloc::boxed::Box<dyn Future<Output = T> + 'a>>;
343
344    /// A pointer type which can be safely shared between threads
345    /// when "sync" feature is enabled.\
346    /// A pointer type which can be shared, but only within single thread
347    /// where it was created when "sync" feature is not enabled.
348    ///
349    /// # Example
350    ///
351    /// ```
352    /// # use {maybe_sync::{MaybeSend, Rc}, std::fmt::Debug};
353    ///
354    /// fn maybe_sends<T: MaybeSend + Debug + 'static>(val: T) {
355    ///   #[cfg(feature = "sync")]
356    ///   {
357    ///     // If this code is compiled then `MaybeSend` is alias to `std::marker::Send`.
358    ///     std::thread::spawn(move || { println!("{:?}", val) });
359    ///   }
360    /// }
361    ///
362    /// // Unlike `std::rc::Rc` this `maybe_sync::Rc<T>` would always
363    /// // satisfy `MaybeSend` bound when `T: MaybeSend + MaybeSync`,
364    /// // even if feature "sync" is enabeld.
365    /// maybe_sends(Rc::new(42));
366    /// ```
367    #[cfg(feature = "alloc")]
368    #[cfg_attr(all(doc, feature = "unstable-doc"), doc(cfg(feature = "alloc")))]
369    pub type Rc<T> = alloc::rc::Rc<T>;
370
371    /// Mutex implementation to use in conjunction with `MaybeSync` bound.
372    ///
373    /// A type alias to `parking_lot::Mutex` when "sync" feature is enabled.\
374    /// A wrapper type around `std::cell::RefCell` when "sync" feature is not enabled.
375    ///
376    /// # Example
377    ///
378    /// ```
379    /// # use {maybe_sync::{MaybeSend, Mutex}, std::{fmt::Debug, sync::Arc}};
380    ///
381    /// fn maybe_sends<T: MaybeSend + Debug + 'static>(val: Arc<Mutex<T>>) {
382    ///   #[cfg(feature = "sync")]
383    ///   {
384    ///     // If this code is compiled then `MaybeSend` is alias to `std::marker::Send`,
385    ///     // and `Mutex` is `parking_lot::Mutex`.
386    ///     std::thread::spawn(move || { println!("{:?}", *val.lock()) });
387    ///   }
388    /// }
389    ///
390    /// // `maybe_sync::Mutex<T>` would always satisfy `MaybeSync` and `MaybeSend`
391    /// // bounds when `T: MaybeSend`,
392    /// // even if feature "sync" is enabeld.
393    /// maybe_sends(Arc::new(Mutex::new(42)));
394    /// ```
395    #[repr(transparent)]
396    #[derive(Debug, Default)]
397    pub struct Mutex<T: ?Sized> {
398        cell: RefCell<T>,
399    }
400
401    impl<T> Mutex<T> {
402        /// Creates a new mutex in an unlocked state ready for use.
403        pub fn new(value: T) -> Self {
404            Mutex {
405                cell: RefCell::new(value),
406            }
407        }
408    }
409
410    impl<T> Mutex<T>
411    where
412        T: ?Sized,
413    {
414        /// Acquires a mutex, blocking the current thread until it is able to do so.\
415        /// This function will block the local thread until it is available to acquire the mutex.\
416        /// Upon returning, the thread is the only thread with the mutex held.\
417        /// An RAII guard is returned to allow scoped unlock of the lock.\
418        /// When the guard goes out of scope, the mutex will be unlocked.\
419        /// Attempts to lock a mutex in the thread which already holds the lock will result in a deadlock.
420        pub fn lock(&self) -> RefMut<T> {
421            self.cell.borrow_mut()
422        }
423
424        /// Attempts to acquire this lock.\
425        /// If the lock could not be acquired at this time, then `None` is returned.\
426        /// Otherwise, an RAII guard is returned.\
427        /// The lock will be unlocked when the guard is dropped.\
428        /// This function does not block.
429        pub fn try_lock(&self) -> Option<RefMut<T>> {
430            self.cell.try_borrow_mut().ok()
431        }
432
433        /// Returns a mutable reference to the underlying data.\
434        /// Since this call borrows the `Mutex` mutably,\
435        /// no actual locking needs to take place -
436        /// the mutable borrow statically guarantees no locks exist.
437        pub fn get_mut(&mut self) -> &mut T {
438            self.cell.get_mut()
439        }
440    }
441
442    /// A boolean type which can be safely shared between threads
443    /// when "sync" feature is enabled.\
444    /// A boolean type with non-threadsafe interior mutability
445    /// when "sync" feature is not enabled.
446    ///
447    /// This type has the same in-memory representation as a bool.
448    pub type AtomicBool = core::cell::Cell<bool>;
449
450    /// A integer type which can be safely shared between threads
451    /// when "sync" feature is enabled.\
452    /// A integer type with non-threadsafe interior mutability
453    /// when "sync" feature is not enabled.
454    ///
455    /// This type has the same in-memory representation as a i8.
456    pub type AtomicI8 = core::cell::Cell<i8>;
457
458    /// A integer type which can be safely shared between threads
459    /// when "sync" feature is enabled.\
460    /// A integer type with non-threadsafe interior mutability
461    /// when "sync" feature is not enabled.
462    ///
463    /// This type has the same in-memory representation as a i16.
464    pub type AtomicI16 = core::cell::Cell<i16>;
465
466    /// A integer type which can be safely shared between threads
467    /// when "sync" feature is enabled.\
468    /// A integer type with non-threadsafe interior mutability
469    /// when "sync" feature is not enabled.
470    ///
471    /// This type has the same in-memory representation as a i32.
472    pub type AtomicI32 = core::cell::Cell<i32>;
473
474    /// A integer type which can be safely shared between threads
475    /// when "sync" feature is enabled.\
476    /// A integer type with non-threadsafe interior mutability
477    /// when "sync" feature is not enabled.
478    ///
479    /// This type has the same in-memory representation as a isize.
480    pub type AtomicIsize = core::cell::Cell<isize>;
481
482    /// A integer type which can be safely shared between threads
483    /// when "sync" feature is enabled.\
484    /// A integer type with non-threadsafe interior mutability
485    /// when "sync" feature is not enabled.
486    ///
487    /// This type has the same in-memory representation as a i8.
488    pub type AtomicU8 = core::cell::Cell<u8>;
489
490    /// A integer type which can be safely shared between threads
491    /// when "sync" feature is enabled.\
492    /// A integer type with non-threadsafe interior mutability
493    /// when "sync" feature is not enabled.
494    ///
495    /// This type has the same in-memory representation as a i16.
496    pub type AtomicU16 = core::cell::Cell<u16>;
497
498    /// A integer type which can be safely shared between threads
499    /// when "sync" feature is enabled.\
500    /// A integer type with non-threadsafe interior mutability
501    /// when "sync" feature is not enabled.
502    ///
503    /// This type has the same in-memory representation as a i32.
504    pub type AtomicU32 = core::cell::Cell<u32>;
505
506    /// A integer type which can be safely shared between threads
507    /// when "sync" feature is enabled.\
508    /// A integer type with non-threadsafe interior mutability
509    /// when "sync" feature is not enabled.
510    ///
511    /// This type has the same in-memory representation as a isize.
512    pub type AtomicUsize = core::cell::Cell<usize>;
513
514    /// A raw pointer type which can be safely shared between threads
515    /// when "sync" feature is enabled.\
516    /// A raw pointer type with non-threadsafe interior mutability
517    /// when "sync" feature is not enabled.
518    ///
519    /// This type has the same in-memory representation as a isize.
520    pub type AtomicPtr<T> = core::cell::Cell<*mut T>;
521}
522
523#[cfg(feature = "sync")]
524pub use sync::*;
525
526#[cfg(not(feature = "sync"))]
527pub use unsync::*;
528
529/// Expands to `dyn $traits` with `Send` marker trait
530/// added when "sync" feature is enabled.
531///
532/// Expands to `dyn $traits` without `Send` marker trait
533/// added "sync" feature is not enabled.
534///
535/// # Example
536/// ```
537/// # use maybe_sync::{MaybeSend, dyn_maybe_send};
538/// fn foo<T: MaybeSend>(_: T) {}
539/// // `x` will implement `MaybeSend` whether "sync" feature is enabled or not.
540/// let x: Box<dyn_maybe_send!(std::future::Future<Output = u32>)> = Box::new(async move { 42 });
541/// foo(x);
542/// ```
543#[cfg(feature = "sync")]
544#[macro_export]
545macro_rules! dyn_maybe_send {
546    ($($traits:tt)+) => {
547        dyn $($traits)+ + Send
548    };
549}
550
551/// Expands to `dyn $traits` with `Send` marker trait
552/// added when "sync" feature is enabled.
553///
554/// Expands to `dyn $traits` without `Send` marker trait
555/// added "sync" feature is not enabled.
556///
557/// # Example
558/// ```
559/// # use maybe_sync::{MaybeSend, dyn_maybe_send};
560/// fn foo<T: MaybeSend>(_: T) {}
561/// // `x` will implement `MaybeSend` whether "sync" feature is enabled or not.
562/// let x: Box<dyn_maybe_send!(std::future::Future<Output = u32>)> = Box::new(async move { 42 });
563/// foo(x);
564/// ```
565#[cfg(not(feature = "sync"))]
566#[macro_export]
567macro_rules! dyn_maybe_send {
568    ($($traits:tt)+) => {
569        dyn $($traits)+
570    };
571}
572
573/// Expands to `dyn $traits` with `Sync` marker trait
574/// added when "sync" feature is enabled.
575///
576/// Expands to `dyn $traits` without `Sync` marker trait
577/// added "sync" feature is not enabled.
578///
579/// # Example
580/// ```
581/// # use maybe_sync::{MaybeSync, dyn_maybe_sync};
582/// fn foo<T: MaybeSync + ?Sized>(_: &T) {}
583///
584/// let x: &dyn_maybe_sync!(AsRef<str>) = &"qwerty";
585/// // `x` will implement `MaybeSync` whether "sync" feature is enabled or not.
586/// foo(x);
587/// ```
588#[cfg(feature = "sync")]
589#[macro_export]
590macro_rules! dyn_maybe_sync {
591    ($($traits:tt)+) => {
592        dyn $($traits)+ + Sync
593    };
594}
595
596/// Expands to `dyn $traits` with `Sync` marker trait
597/// added when "sync" feature is enabled.
598///
599/// Expands to `dyn $traits` without `Sync` marker trait
600/// added "sync" feature is not enabled.
601///
602/// # Example
603/// ```
604/// # use maybe_sync::{MaybeSync, dyn_maybe_sync};
605/// fn foo<T: MaybeSync + ?Sized>(_: &T) {}
606/// // `x` will implement `MaybeSync` whether "sync" feature is enabled or not.
607/// let x: &dyn_maybe_sync!(AsRef<str>) = &"qwerty";
608/// foo(x);
609/// ```
610#[cfg(not(feature = "sync"))]
611#[macro_export]
612macro_rules! dyn_maybe_sync {
613    ($($traits:tt)+) => {
614        dyn $($traits)+
615    };
616}
617
618/// Expands to `dyn $traits` with `Send` and `Sync` marker trait
619/// added when "sync" feature is enabled.
620///
621/// Expands to `dyn $traits` without `Send` and `Sync` marker trait
622/// added "sync" feature is not enabled.
623///
624/// # Example
625/// ```
626/// # use maybe_sync::{MaybeSend, MaybeSync, dyn_maybe_send_sync};
627/// fn foo<T: MaybeSend + MaybeSync + ?Sized>(_: &T) {}
628/// // `x` will implement `MaybeSend` and `MaybeSync` whether "sync" feature is enabled or not.
629/// let x: &dyn_maybe_send_sync!(AsRef<str>) = &"qwerty";
630/// foo(x);
631/// ```
632#[cfg(feature = "sync")]
633#[macro_export]
634macro_rules! dyn_maybe_send_sync {
635    ($($traits:tt)+) => {
636        dyn $($traits)+ + Send + Sync
637    };
638}
639
640/// Expands to `dyn $traits` with `Sync` marker trait
641/// added when "sync" feature is enabled.
642///
643/// Expands to `dyn $traits` without `Sync` marker trait
644/// added "sync" feature is not enabled.
645///
646/// # Example
647/// ```
648/// # use maybe_sync::{MaybeSend, MaybeSync, dyn_maybe_send_sync};
649/// fn foo<T: MaybeSend + MaybeSync + ?Sized>(_: &T) {}
650/// // `x` will implement `MaybeSend` and `MaybeSync` whether "sync" feature is enabled or not.
651/// let x: &dyn_maybe_send_sync!(AsRef<str>) = &"qwerty";
652/// foo(x);
653/// ```
654#[cfg(not(feature = "sync"))]
655#[macro_export]
656macro_rules! dyn_maybe_send_sync {
657    ($($traits:tt)+) => {
658        dyn $($traits)+
659    };
660}