ty_tag/
modifiers.rs

1//! Tag modifiers.
2//!
3//! Types in the module wrap other tagged types to modify them in some way.
4
5use core::marker::PhantomData;
6use core::ops::{Deref, DerefMut};
7
8use crate::lifetime_list::cons::Cons;
9use crate::lifetime_list::{Hole, HoleList, LifetimeList, H0, L0};
10use crate::{Tag, Tagged, WithLt};
11
12/// Require an extra lifetime at the beginning.
13///
14/// If `T` needed `['a, 'b, 'c]` then `AddLt<T>` needs `['x, 'a, 'b, 'c]`.
15///
16/// # Examples
17///
18/// ```
19/// # #[cfg(all(feature = "macros", feature = "core"))]
20/// # fn run() {
21/// use ty_tag::{tag, modifiers::AddLt, Reify, l};
22///
23/// fn with_lt<'a>() {
24///     // error: lifetime may not live long enough
25///     // is_tagged::<'a, &str, &'static str>();
26///
27///     is_tagged::<'a, AddLt<&str>, &'static str>();
28/// }
29/// with_lt();
30///
31/// // Checks that T reifies to U.
32/// fn is_tagged<'a, T: Reify<l!['a], Reified = U>, U>() {}
33/// # }
34/// # #[cfg(all(feature = "macros", feature = "core"))]
35/// # run();
36/// ```
37pub struct AddLt<T: ?Sized>(PhantomData<fn() -> *const T>);
38
39impl<Group: ?Sized, T: ?Sized + Tagged<Group>> Tagged<Group> for AddLt<T> {
40    type Tag = AddLt<T::Tag>;
41}
42
43impl<T: Tag> Tag for AddLt<T> {
44    type NeededLifetimes = Cons<Hole, T::NeededLifetimes>;
45}
46
47impl<T: WithLt<L::Tail>, L: LifetimeList> WithLt<L> for AddLt<T> {
48    type Reified = T::Reified;
49}
50
51/// Merges the first two needed lifetimes.
52///
53/// If `T` needed `['a, 'b, 'c]` then `RepeatLt<T>` needs `['b, 'c]` where `'b` will be used
54/// where `'a` is needed in `T`.
55///
56/// This can be useful for trait objects where you want `&'a (dyn Trait + 'a)` instead
57/// of `&'a (dyn Trait + 'b)`.
58///
59/// # Examples
60///
61/// ```
62/// # #[cfg(all(feature = "macros", feature = "core"))]
63/// # fn run() {
64/// use ty_tag::{tag, modifiers::RepeatLt, Reify, l};
65///
66/// // Some random trait.
67/// trait X {}
68///
69/// // We tag the trait object.
70/// #[tag]
71/// type Tag<'a> = dyn X + 'a;
72///
73/// fn with_lt<'a>() {
74///     // error: lifetime may not live long enough
75///     // is_tagged::<&dyn X, &'a (dyn X + 'a)>();
76///
77///     is_tagged::<RepeatLt<&dyn X>, &'a (dyn X + 'a)>();
78/// }
79/// with_lt();
80///
81/// // Checks that T reifies to U.
82/// fn is_tagged<'a, T: Reify<l!['a], Reified = U>, U>() {}
83/// # }
84/// # #[cfg(all(feature = "macros", feature = "core"))]
85/// # run();
86/// ```
87pub struct RepeatLt<T: ?Sized>(PhantomData<fn() -> *const T>);
88
89impl<Group: ?Sized, T: ?Sized + Tagged<Group>> Tagged<Group> for RepeatLt<T> {
90    type Tag = RepeatLt<T::Tag>;
91}
92
93impl<T: Tag> Tag for RepeatLt<T> {
94    type NeededLifetimes = <T::NeededLifetimes as HoleList>::HoleTail;
95}
96
97impl<T: WithLt<Cons<L::Head, L>>, L: LifetimeList> WithLt<L> for RepeatLt<T>
98where
99    Cons<L::Head, L>: LifetimeList,
100{
101    type Reified = T::Reified;
102}
103
104/// Use the tag from another group.
105///
106/// Not all types are tagged within a given group. This modifier allows switching the group
107/// locally.
108///
109/// The `Group` type is the group that should be used to get the tag from `T`.
110///
111/// # Examples
112///
113/// ```
114/// # #[cfg(all(feature = "macros", feature = "core"))]
115/// # fn run() {
116/// use ty_tag::{tag, modifiers::InGroup, Reify};
117///
118/// // A custom group.
119/// struct MyGroup;
120///
121/// // Some random type.
122/// struct X;
123///
124/// // We tag the type X in the group MyGroup.
125/// #[tag(remote, group = MyGroup)]
126/// type Tag = X;
127///
128/// // error[E0277]: the trait bound `Fundamental: Tags<X>` is not satisfied
129/// // is_tagged::<X, X>();
130///
131/// // InGroup uses the tag for X in MyGroup.
132/// is_tagged::<InGroup<X, MyGroup>, X>();
133///
134/// // Checks that T reifies to U.
135/// fn is_tagged<T: Reify<Reified = U>, U>() {}
136/// # }
137/// # #[cfg(all(feature = "macros", feature = "core"))]
138/// # run();
139/// ```
140pub struct InGroup<T: ?Sized, Group: ?Sized>(PhantomData<fn() -> (*const T, *const Group)>);
141
142impl<T: Tagged<Group>, Group: ?Sized, OtherGroup: ?Sized> Tagged<OtherGroup> for InGroup<T, Group> {
143    type Tag = <T as Tagged<Group>>::Tag;
144}
145
146pub struct Owned<T: ?Sized>(PhantomData<fn() -> *const T>);
147
148impl<T: ?Sized + 'static, Group> Tagged<Group> for Owned<T> {
149    type Tag = Self;
150}
151
152impl<T: ?Sized + 'static> Tag for Owned<T> {
153    type NeededLifetimes = H0;
154}
155
156impl<T: ?Sized + 'static> WithLt<L0> for Owned<T> {
157    type Reified = T;
158}
159
160/// Wrapper that reports as being tagged by a specific tag.
161///
162/// Not all types implement [`Tagged`]. This wrapper can be used in those cases
163/// to have a type that with reify to itself after using it's tag.
164#[repr(transparent)]
165pub struct Label<Tag: WithLt<L>, L: LifetimeList = L0>(pub <Tag as WithLt<L>>::Reified);
166
167impl<L: LifetimeList, Tag: WithLt<L>> Label<Tag, L>
168where
169    Tag::Reified: Sized,
170{
171    pub const fn new(value: <Tag as WithLt<L>>::Reified) -> Self {
172        Self(value)
173    }
174
175    #[cfg(feature = "unsafe")]
176    pub const fn into_inner(self) -> <Tag as WithLt<L>>::Reified {
177        let this = core::mem::ManuallyDrop::new(self);
178        unsafe { core::mem::transmute_copy(&this) }
179    }
180}
181
182#[cfg(feature = "unsafe")]
183impl<L: LifetimeList, Tag: WithLt<L>> Label<Tag, L> {
184    pub const fn from_ref(value: &<Tag as WithLt<L>>::Reified) -> &Self {
185        unsafe { &*(core::ptr::from_ref(value) as *const Self) }
186    }
187
188    pub const fn from_mut(value: &mut <Tag as WithLt<L>>::Reified) -> &mut Self {
189        unsafe { &mut *(core::ptr::from_mut(value) as *mut Self) }
190    }
191
192    pub const fn to_ref(&self) -> &<Tag as WithLt<L>>::Reified {
193        unsafe { &*(core::ptr::from_ref(self) as *const _) }
194    }
195
196    pub const fn to_mut(&mut self) -> &mut <Tag as WithLt<L>>::Reified {
197        unsafe { &mut *(core::ptr::from_mut(self) as *mut _) }
198    }
199}
200
201impl<L: LifetimeList, Tag: WithLt<L>> Deref for Label<Tag, L> {
202    type Target = <Tag as WithLt<L>>::Reified;
203
204    fn deref(&self) -> &Self::Target {
205        &self.0
206    }
207}
208
209impl<L: LifetimeList, Tag: WithLt<L>> DerefMut for Label<Tag, L> {
210    fn deref_mut(&mut self) -> &mut Self::Target {
211        &mut self.0
212    }
213}
214
215const _: () = {
216    pub struct __<T>(T);
217
218    impl<Group: ?Sized, L: LifetimeList, T: WithLt<L>> Tagged<Group> for Label<T, L> {
219        type Tag = __<T>;
220    }
221
222    impl<Group: ?Sized, T: Tagged<Group>> Tagged<Group> for __<T> {
223        type Tag = __<T::Tag>;
224    }
225
226    impl<T: Tag> Tag for __<T> {
227        type NeededLifetimes = T::NeededLifetimes;
228    }
229
230    impl<L: LifetimeList, T: WithLt<L>> WithLt<L> for __<T> {
231        type Reified = Label<T, L>;
232    }
233};