generic_container/kinds.rs
1//! # Container Kind Traits
2//!
3//! Currently, Rust doesn't allow bounds like
4//! `where C: for<T: Send> Container<T> + Clone + Send + Sync`.
5//! The solution is to define an extra trait with whatever you need as the bounds of a GAT
6//! (generic associated type):
7//! ```
8//! use generic_container::FragileMutContainer;
9//! use dupe::Dupe;
10//!
11//! pub trait NeededContainerStuff {
12//! // Implementors should use `T: ?Sized` when possible. But right now, the only way to create,
13//! // for example, `Arc<Mutex<[T]>>` is via unsizing coercion from `Arc<Mutex<[T; N]>>`;
14//! // as such, a `T: ?Sized` bound would be somewhat useless without also requiring the
15//! // container to support unsizing coercion, which currently requires nightly-only traits.
16//! type MutableContainer<T: Send>: FragileMutContainer<T> + Dupe + Send + Sync;
17//! }
18//! ```
19//!
20//! If some data needs thread-safe mutability, but you don't want to pay the cost of a lock for
21//! read-only data, you can use multiple GATs:
22//! ```
23//! use generic_container::{FragileMutContainer, Container};
24//! use dupe::Dupe;
25//!
26//! pub trait NeededContainerStuff {
27//! // E.g.: `Arc<Mutex<T>>`, or something `parking_lot`-based
28//! type MutableContainer<T: Send>: FragileMutContainer<T> + Dupe + Send + Sync;
29//! // E.g.: `Arc<T>`
30//! type ReadOnlyContainer<T: Send + Sync>: Container<T> + Dupe + Send + Sync;
31//! }
32//! ```
33//!
34//! Such a trait is called a "container kind trait" (with implementations being "container kinds",
35//! just as implementations of the container traits are "containers"). Relevant characteristics for
36//! a container kind's container include the eight container traits, `Send + Sync` bounds (possibly
37//! only when `T` is `Send + Sync`, or just `Send`), [`Dupe`], whether the GAT allows `T` to be
38//! unsized, and `Debug` bounds.
39//!
40//! Not every conceivably-useful container kind trait is provided, as there would be
41//! exponentially-many such traits. Note also that creating simple container kind traits that can
42//! be combined into more complicated bounds does *work*, but not well. A container kind should set
43//! the GAT of each container kind trait it implements to the same container type; this *can* be
44//! asserted or required with Rust's type system, but the trait solver doesn't understand it very
45//! well. Such container kind traits would likely not be pleasant to use.
46//!
47//! When the `kinds` feature is enabled, container kinds for common sorts of containers are
48//! provided. They do not use [`Dupe`] bounds, and do not mess with type-equality shenanigans that
49//! confuse the trait solver.
50//!
51//! [`Dupe`]: https://docs.rs/dupe/0.9/dupe/trait.Dupe.html
52
53use crate::container_traits::{
54 Container, FragileContainer, FragileMutContainer, MutContainer, TryMutContainer,
55};
56
57
58// ================================
59// Container Kind Traits
60// ================================
61
62/// A [container kind trait](self) based on how a type `T` acts as a container for itself.
63///
64/// Has strictly tighter requirements than [`FragileTLike`].
65pub trait TLike {
66 /// A `T`-like container type
67 type Container<T>: MutContainer<T>;
68}
69
70/// A [container kind trait](self) based on how a type `T` acts as a container for itself.
71///
72/// `T`, however, is not a [fragile](crate#fragility-potential-panics-or-deadlocks) container;
73/// this kind trait loosens that requirement.
74pub trait FragileTLike {
75 /// A `T`-like container type, but permitted to be
76 /// [fragile](crate#fragility-potential-panics-or-deadlocks).
77 type Container<T>: FragileMutContainer<T>;
78}
79
80/// A [container kind trait](self) based on how `Box<T>` acts as a container for `T`.
81///
82/// Has strictly tighter requirements than [`TLike`], [`FragileTLike`], and [`FragileBoxLike`].
83pub trait BoxLike {
84 /// A `Box<T>`-like container type
85 type Container<T: ?Sized>: MutContainer<T>;
86}
87
88/// A [container kind trait](self) based on how `Box<T>` acts as a container for `T`.
89///
90/// `Box<T>`, however, is not a [fragile](crate#fragility-potential-panics-or-deadlocks) container;
91/// this kind trait loosens that requirement.
92///
93/// Has strictly tighter requirements than [`FragileTLike`].
94pub trait FragileBoxLike {
95 /// A `Box<T>`-like container type, but permitted to be
96 /// [fragile](crate#fragility-potential-panics-or-deadlocks).
97 type Container<T: ?Sized>: FragileMutContainer<T>;
98}
99
100/// A [container kind trait](self) based on how `Rc<T>` acts as a container for `T`.
101///
102/// Has strictly tighter requirements than [`FragileRcLike`].
103pub trait RcLike {
104 /// An `Rc<T>`-like container type
105 type Container<T: ?Sized>: Container<T> + Clone;
106}
107
108/// A [container kind trait](self) based on how `Rc<T>` acts as a container for `T`.
109///
110/// `Rc<T>`, however, is not a [fragile](crate#fragility-potential-panics-or-deadlocks) container;
111/// this kind trait loosens that requirement.
112pub trait FragileRcLike {
113 /// An `Rc<T>`-like container type, but permitted to be
114 /// [fragile](crate#fragility-potential-panics-or-deadlocks).
115 type Container<T: ?Sized>: FragileContainer<T> + Clone;
116}
117
118/// A [container kind trait](self) based on how `Rc<RefCell<T>>` acts as a container for `T`.
119///
120/// Has strictly tighter requirements than [`FragileRcLike`].
121pub trait RcRefCellLike {
122 /// An `Rc<RefCell<T>>`-like container type
123 type Container<T: ?Sized>: FragileMutContainer<T> + Clone;
124}
125
126/// A [container kind trait](self) based on how `Arc<T>` acts as a container for `T`.
127///
128/// Has strictly tighter requirements than [`FragileArcLike`].
129pub trait ArcLike {
130 /// An `Arc<T>`-like container type
131 type Container<T: ?Sized + Send + Sync>: Container<T> + Clone + Send + Sync;
132}
133
134/// A [container kind trait](self) based on how `Arc<T>` acts as a container for `T`.
135///
136/// `Arc<T>`, however, is not a [fragile](crate#fragility-potential-panics-or-deadlocks) container;
137/// this kind trait loosens that requirement.
138pub trait FragileArcLike {
139 /// An `Arc<T>`-like container type, but permitted to be
140 /// [fragile](crate#fragility-potential-panics-or-deadlocks).
141 type Container<T: ?Sized + Send + Sync>: FragileContainer<T> + Clone + Send + Sync;
142}
143
144/// A [container kind trait](self) based on how `Arc<RwLock<T>>` acts as a container for `T`.
145///
146/// Has strictly tighter requirements than [`FragileArcLike`].
147/// Similar to [`RcRefCellLike`], but not strictly tighter.
148pub trait ArcRwLockLike {
149 /// An `Arc<RwLock<T>>`-like container type
150 type Container<T: ?Sized + Send + Sync>: FragileMutContainer<T> + Clone + Send + Sync;
151}
152
153/// A [container kind trait](self) based on how `Arc<Mutex<T>>` acts as a container for `T`.
154///
155/// Has strictly tighter requirements than [`ArcRwLockLike`] and [`FragileArcLike`].
156/// Similar to [`RcRefCellLike`], but not strictly tighter.
157pub trait ArcMutexLike {
158 /// An `Arc<Mutex<T>>`-like container type
159 type Container<T: ?Sized + Send>: FragileMutContainer<T> + Clone + Send + Sync;
160}
161
162/// A [container kind trait](self) based on how [`CheckedRcRefCell<T>`] acts as a container for `T`.
163///
164#[cfg_attr(
165 feature = "alloc",
166 doc = "[`CheckedRcRefCell<T>`]: crate::CheckedRcRefCell",
167)]
168#[cfg_attr(
169 not(feature = "alloc"),
170 doc = "[`CheckedRcRefCell<T>`]: \
171 https://docs.rs/generic-container/0/generic_container/struct.CheckedRcRefCell.html",
172)]
173pub trait CheckedRcRefCellLike {
174 /// A [`CheckedRcRefCell<T>`]-like container type
175 ///
176 #[cfg_attr(
177 feature = "alloc",
178 doc = "[`CheckedRcRefCell<T>`]: crate::CheckedRcRefCell",
179 )]
180 #[cfg_attr(
181 not(feature = "alloc"),
182 doc = "[`CheckedRcRefCell<T>`]: \
183 https://docs.rs/generic-container/0/generic_container/struct.CheckedRcRefCell.html",
184 )]
185 type Container<T: ?Sized>: TryMutContainer<T> + Clone;
186}
187
188/// A [container kind trait](self) based on how <code>Arc<[ThreadCheckedMutex]\<T\>></code> acts as
189/// a container for `T`.
190///
191#[cfg_attr(
192 feature = "thread-checked-lock",
193 doc = "[ThreadCheckedMutex]: thread_checked_lock::ThreadCheckedMutex",
194)]
195#[cfg_attr(
196 not(feature = "thread-checked-lock"),
197 doc = "[ThreadCheckedMutex]: \
198 https://docs.rs/thread-checked-lock/0/thread_checked_lock/struct.ThreadCheckedMutex.html",
199)]
200pub trait ArcThreadCheckedMutexLike {
201 /// An <code>Arc<[ThreadCheckedMutex]\<T\>></code>-like container type
202 ///
203 #[cfg_attr(
204 feature = "thread-checked-lock",
205 doc = "[ThreadCheckedMutex]: thread_checked_lock::ThreadCheckedMutex",
206 )]
207 #[cfg_attr(
208 not(feature = "thread-checked-lock"),
209 doc = "[ThreadCheckedMutex]: \
210 https://docs.rs/thread-checked-lock/0/thread_checked_lock/struct.ThreadCheckedMutex.html",
211 )]
212 type Container<T: ?Sized + Send>: TryMutContainer<T> + Clone + Send + Sync;
213}
214
215// ================================
216// Container Kinds
217// ================================
218
219/// The [container kind](crate::kinds) corresponding to `T` as a container for itself.
220#[cfg_attr(docsrs, doc(cfg(feature = "kinds")))]
221#[derive(Default, Debug, Clone, Copy)]
222pub struct TKind;
223
224impl TLike for TKind {
225 type Container<T> = T;
226}
227
228impl FragileTLike for TKind {
229 type Container<T> = T;
230}
231
232#[cfg(any(feature = "alloc", doc))]
233mod alloc_kinds {
234 use core::cell::RefCell;
235 use alloc::{boxed::Box, rc::Rc, sync::Arc};
236
237 use crate::impls::CheckedRcRefCell;
238 use super::{
239 ArcLike, BoxLike, CheckedRcRefCellLike,
240 FragileArcLike, FragileBoxLike, FragileTLike, FragileRcLike,
241 RcLike, RcRefCellLike, TLike,
242 };
243
244
245 /// The [container kind](crate::kinds) corresponding to `Box<T>` as a container for `T`.
246 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "kinds"))))]
247 #[derive(Default, Debug, Clone, Copy)]
248 pub struct BoxKind;
249
250 impl BoxLike for BoxKind {
251 type Container<T: ?Sized> = Box<T>;
252 }
253
254 impl FragileBoxLike for BoxKind {
255 type Container<T: ?Sized> = Box<T>;
256 }
257
258 impl TLike for BoxKind {
259 type Container<T> = Box<T>;
260 }
261
262 impl FragileTLike for BoxKind {
263 type Container<T> = Box<T>;
264 }
265
266 /// The [container kind](crate::kinds) corresponding to `Rc<T>` as a container for `T`.
267 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "kinds"))))]
268 #[derive(Default, Debug, Clone, Copy)]
269 pub struct RcKind;
270
271 impl RcLike for RcKind {
272 type Container<T: ?Sized> = Rc<T>;
273 }
274
275 impl FragileRcLike for RcKind {
276 type Container<T: ?Sized> = Rc<T>;
277 }
278
279 /// The [container kind](crate::kinds) corresponding to `Arc<T>` as a container for `T`.
280 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "kinds"))))]
281 #[derive(Default, Debug, Clone, Copy)]
282 pub struct ArcKind;
283
284 impl ArcLike for ArcKind {
285 type Container<T: ?Sized + Send + Sync> = Arc<T>;
286 }
287
288 impl FragileArcLike for ArcKind {
289 type Container<T: ?Sized + Send + Sync> = Arc<T>;
290 }
291
292 impl RcLike for ArcKind {
293 type Container<T: ?Sized> = Arc<T>;
294 }
295
296 impl FragileRcLike for ArcKind {
297 type Container<T: ?Sized> = Arc<T>;
298 }
299
300 /// The [container kind](crate::kinds) corresponding to `Rc<RefCell<T>>` as a container for `T`.
301 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "kinds"))))]
302 #[derive(Default, Debug, Clone, Copy)]
303 pub struct RcRefCellKind;
304
305 impl RcRefCellLike for RcRefCellKind {
306 type Container<T: ?Sized> = Rc<RefCell<T>>;
307 }
308
309 impl FragileRcLike for RcRefCellKind {
310 type Container<T: ?Sized> = Rc<RefCell<T>>;
311 }
312
313 /// The [container kind](crate::kinds) corresponding to [`CheckedRcRefCell<T>`] as a container
314 /// for `T`.
315 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "kinds"))))]
316 #[derive(Default, Debug, Clone, Copy)]
317 pub struct CheckedRcRefCellKind;
318
319 impl CheckedRcRefCellLike for CheckedRcRefCellKind {
320 type Container<T: ?Sized> = CheckedRcRefCell<T>;
321 }
322}
323
324#[cfg(any(feature = "alloc", doc))]
325pub use self::alloc_kinds::{ArcKind, BoxKind, CheckedRcRefCellKind, RcKind, RcRefCellKind};
326
327#[cfg(any(feature = "std", doc))]
328mod std_kinds {
329 use alloc::sync::Arc;
330 use std::sync::{Mutex, RwLock};
331
332 use super::{ArcMutexLike, ArcRwLockLike, FragileArcLike, FragileRcLike, RcRefCellLike};
333
334
335 /// The [container kind](crate::kinds) corresponding to `Arc<RwLock<T>>` as a container for `T`.
336 #[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "kinds"))))]
337 #[derive(Default, Debug, Clone, Copy)]
338 pub struct ArcRwLockKind;
339
340 impl ArcRwLockLike for ArcRwLockKind {
341 type Container<T: ?Sized + Send + Sync> = Arc<RwLock<T>>;
342 }
343
344 impl FragileArcLike for ArcRwLockKind {
345 type Container<T: ?Sized + Send + Sync> = Arc<RwLock<T>>;
346 }
347
348 impl RcRefCellLike for ArcRwLockKind {
349 type Container<T: ?Sized> = Arc<RwLock<T>>;
350 }
351
352 impl FragileRcLike for ArcRwLockKind {
353 type Container<T: ?Sized> = Arc<RwLock<T>>;
354 }
355
356 /// The [container kind](crate::kinds) corresponding to `Arc<Mutex<T>>` as a container for `T`.
357 #[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "kinds"))))]
358 #[derive(Default, Debug, Clone, Copy)]
359 pub struct ArcMutexKind;
360
361 impl ArcMutexLike for ArcMutexKind {
362 type Container<T: ?Sized + Send> = Arc<Mutex<T>>;
363 }
364
365 impl ArcRwLockLike for ArcMutexKind {
366 type Container<T: ?Sized + Send + Sync> = Arc<Mutex<T>>;
367 }
368
369 impl FragileArcLike for ArcMutexKind {
370 type Container<T: ?Sized + Send + Sync> = Arc<Mutex<T>>;
371 }
372
373 impl RcRefCellLike for ArcMutexKind {
374 type Container<T: ?Sized> = Arc<Mutex<T>>;
375 }
376
377 impl FragileRcLike for ArcMutexKind {
378 type Container<T: ?Sized> = Arc<Mutex<T>>;
379 }
380}
381
382#[cfg(any(feature = "std", doc))]
383pub use self::std_kinds::{ArcMutexKind, ArcRwLockKind};
384
385#[cfg(feature = "thread-checked-lock")]
386mod thread_checked_lock_kinds {
387 use alloc::sync::Arc;
388
389 use thread_checked_lock::ThreadCheckedMutex;
390
391 use super::{ArcThreadCheckedMutexLike, CheckedRcRefCellLike};
392
393
394 /// The [container kind](crate::kinds) corresponding to
395 /// <code>[Arc]<[ThreadCheckedMutex]\<T\>></code> as a container for `T`.
396 #[cfg_attr(docsrs, doc(cfg(all(feature = "thread-checked-lock", feature = "kinds"))))]
397 #[derive(Default, Debug, Clone, Copy)]
398 pub struct ArcThreadCheckedMutexKind;
399
400 impl ArcThreadCheckedMutexLike for ArcThreadCheckedMutexKind {
401 type Container<T: ?Sized + Send> = Arc<ThreadCheckedMutex<T>>;
402 }
403
404 impl CheckedRcRefCellLike for ArcThreadCheckedMutexKind {
405 type Container<T: ?Sized> = Arc<ThreadCheckedMutex<T>>;
406 }
407}
408
409#[cfg(feature = "thread-checked-lock")]
410pub use self::thread_checked_lock_kinds::ArcThreadCheckedMutexKind;