|
1 | 1 | #![no_std] |
2 | | -#![forbid(unsafe_code)] |
3 | 2 | // reasonable clippy categories |
4 | 3 | #![warn(clippy::pedantic, clippy::nursery, clippy::cargo)] |
5 | 4 | // reasonable clippy::restriction lints |
|
88 | 87 | //! [![crates.io]](https://crates.io/crates/existential) |
89 | 88 | //! [![github]](https://github.com/steffahn/existential) |
90 | 89 | //! [![MIT / Apache 2.0 licensed]](https://github.com/steffahn/existential#License) |
91 | | -//! [![unsafe forbidden]](https://github.com/rust-secure-code/safety-dance/) |
92 | 90 | //! |
93 | 91 | //! [Existential types](https://wiki.haskell.org/Existential_type) in Rust, offering existential |
94 | 92 | //! quantification over lifetimes, but as a library. This works because Rust has |
95 | 93 | //! [parametricity](https://en.wikipedia.org/wiki/Parametricity) for generic lifetime arguments. |
96 | 94 | //! |
97 | | -//! _Work in progress; this crate is still undocumented._ |
| 95 | +//! _TODO: this crate is still undocumented._ |
98 | 96 | //! |
99 | 97 | //! [github]: https://img.shields.io/badge/github-steffahn/existential-yellowgreen.svg |
100 | 98 | //! [crates.io]: https://img.shields.io/crates/v/existential.svg |
101 | 99 | //! [MIT / Apache 2.0 licensed]: https://img.shields.io/crates/l/existential.svg |
102 | 100 | //! [docs.rs]: https://docs.rs/existential/badge.svg |
103 | | -//! [unsafe forbidden]: https://img.shields.io/badge/unsafe-forbidden-success.svg |
| 101 | +
|
| 102 | +use core::{ |
| 103 | + marker::PhantomData, |
| 104 | + mem::{self, ManuallyDrop}, |
| 105 | +}; |
| 106 | + |
| 107 | +pub trait TyConFor<'a> { |
| 108 | + type Applied; |
| 109 | +} |
| 110 | + |
| 111 | +pub type Apply<'a, C> = <C as TyConFor<'a>>::Applied; |
| 112 | + |
| 113 | +pub trait TyCon: for<'a> TyConFor<'a> {} |
| 114 | +impl<C: ?Sized> TyCon for C where C: for<'a> TyConFor<'a> {} |
| 115 | + |
| 116 | +pub struct Existential<'lower_bound, C> |
| 117 | +where |
| 118 | + C: TyCon, |
| 119 | +{ |
| 120 | + marker: PhantomData<&'lower_bound ()>, |
| 121 | + inner: Apply<'static, C>, |
| 122 | +} |
| 123 | + |
| 124 | +impl<'lower_bound, C> Existential<'lower_bound, C> |
| 125 | +where |
| 126 | + C: TyCon, |
| 127 | +{ |
| 128 | + pub fn new<'a: 'lower_bound>(inner: Apply<'a, C>) -> Existential<'lower_bound, C> { |
| 129 | + let inner = ManuallyDrop::new(inner); |
| 130 | + unsafe { |
| 131 | + Self { |
| 132 | + marker: PhantomData, |
| 133 | + inner: mem::transmute_copy::<Apply<'a, C>, Apply<'static, C>>(&inner), |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + pub fn with<'s, F, O>(&'s self, f: F) -> O |
| 138 | + where |
| 139 | + F: for<'a> FnOnce(&'s Apply<'a, C>, PhantomData<&'lower_bound &'a ()>) -> O, |
| 140 | + { |
| 141 | + f(&self.inner, PhantomData) |
| 142 | + } |
| 143 | + pub fn with_mut<'s, F, O>(&'s mut self, f: F) -> O |
| 144 | + where |
| 145 | + F: for<'a> FnOnce(&'s mut Apply<'a, C>, PhantomData<&'lower_bound &'a ()>) -> O, |
| 146 | + { |
| 147 | + f(&mut self.inner, PhantomData) |
| 148 | + } |
| 149 | + pub fn with_owned<F, O>(self, f: F) -> O |
| 150 | + where |
| 151 | + F: for<'a> FnOnce(Apply<'a, C>, PhantomData<&'lower_bound &'a ()>) -> O, |
| 152 | + { |
| 153 | + f(self.inner, PhantomData) |
| 154 | + } |
| 155 | +} |
0 commit comments