generic_container/
generic_container.rs

1#![warn(
2    clippy::missing_inline_in_public_items,
3    reason = "the wrapper type should mostly just delegate",
4)]
5
6use core::{cmp::Ordering, marker::PhantomData};
7use core::{
8    fmt::{Debug, Formatter, Result as FmtResult},
9    hash::{Hash, Hasher},
10};
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15
16// Default, Debug, Copy, Clone, PartialEq<Self>, Eq, PartialOrd<Self>, Ord, and Hash are all
17// manually implemented and defer to the container.
18/// A wrapper type intended for use in blanket implementations of `YourTrait` ranging over
19/// containers `C` that hold a `T: YourTrait`.
20///
21/// This is necessary to avoid conflicting trait implementations.
22///
23/// ## Examples
24/// Not needed when the `T: YourTrait` is fixed:
25/// ```
26/// use generic_container::Container;
27///
28/// trait Trait {
29///     fn do_thing(&self);
30/// }
31///
32/// impl<C: ?Sized + Container<dyn Trait>> Trait for C {
33///     fn do_thing(&self) {
34///         self.get_ref().do_thing();
35///     }
36/// }
37/// ```
38///
39/// But when the inner type varies:
40/// ```
41/// use generic_container::{Container, GenericContainer};
42///
43/// trait Trait {
44///     fn do_thing(&self);
45/// }
46///
47/// impl<T: ?Sized + Trait, C: ?Sized + Container<T>> Trait for GenericContainer<T, C> {
48///     fn do_thing(&self) {
49///         self.container.get_ref().do_thing();
50///     }
51/// }
52/// ```
53///
54/// Without a wrapper type, it does not compile:
55/// ```compile_fail
56/// use generic_container::{Container, GenericContainer};
57///
58/// trait Trait {
59///     fn do_thing(&self);
60/// }
61///
62/// impl<T: ?Sized + Trait, C: ?Sized + Container<T>> Trait for C {
63///     fn do_thing(&self) {
64///         self.get_ref().do_thing();
65///     }
66/// }
67/// ```
68#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
69#[repr(transparent)]
70pub struct GenericContainer<T: ?Sized, C: ?Sized> {
71    /// Distinguish which type is supposed to be contained.
72    pub _marker:   PhantomData<T>,
73    /// Should implement the base container trait, [`FragileTryContainer<T>`].
74    ///
75    /// [`FragileTryContainer<T>`]: crate::container_traits::FragileTryContainer
76    pub container: C,
77}
78
79impl<T: ?Sized, C> GenericContainer<T, C> {
80    /// Create a new `GenericContainer` struct wrapping the provided value, treated as a container
81    /// around a specific type.
82    #[inline]
83    #[must_use]
84    pub const fn new(container: C) -> Self {
85        Self {
86            _marker: PhantomData,
87            container,
88        }
89    }
90}
91
92impl<T: ?Sized, C: Default> Default for GenericContainer<T, C> {
93    #[inline]
94    fn default() -> Self {
95        Self::new(C::default())
96    }
97}
98
99impl<T, C> Debug for GenericContainer<T, C>
100where
101    T: ?Sized,
102    C: ?Sized + Debug,
103{
104    #[allow(clippy::missing_inline_in_public_items, reason = "not trivial or likely to be hot")]
105    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
106        f.debug_struct("GenericContainer")
107            .field("_marker", &self._marker)
108            .field("container", &&self.container)
109            .finish()
110    }
111}
112
113impl<T: ?Sized, C: Copy> Copy for GenericContainer<T, C> {}
114
115impl<T: ?Sized, C: Clone> Clone for GenericContainer<T, C> {
116    #[inline]
117    fn clone(&self) -> Self {
118        Self {
119            _marker:   self._marker,
120            container: self.container.clone(),
121        }
122    }
123
124    #[inline]
125    fn clone_from(&mut self, source: &Self) {
126        self.container.clone_from(&source.container);
127    }
128}
129
130impl<T: ?Sized, C: ?Sized + PartialEq<C>> PartialEq<Self> for GenericContainer<T, C> {
131    #[inline]
132    fn eq(&self, other: &Self) -> bool {
133        self.container.eq(&other.container)
134    }
135}
136
137impl<T: ?Sized, C: ?Sized + Eq> Eq for GenericContainer<T, C> {}
138
139impl<T: ?Sized, C: ?Sized + PartialOrd<C>> PartialOrd<Self> for GenericContainer<T, C> {
140    #[inline]
141    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
142        self.container.partial_cmp(&other.container)
143    }
144}
145
146impl<T: ?Sized, C: ?Sized + Ord> Ord for GenericContainer<T, C> {
147    #[inline]
148    fn cmp(&self, other: &Self) -> Ordering {
149        self.container.cmp(&other.container)
150    }
151}
152
153impl<T: ?Sized, C: ?Sized + Hash> Hash for GenericContainer<T, C> {
154    #[inline]
155    fn hash<H: Hasher>(&self, state: &mut H) {
156        self.container.hash(state);
157    }
158}