existential/
lib.rs

1#![no_std]
2// reasonable clippy categories
3#![warn(clippy::pedantic, clippy::nursery, clippy::cargo)]
4// reasonable clippy::restriction lints
5#![warn(
6    clippy::as_conversions,
7    clippy::clone_on_ref_ptr,
8    clippy::create_dir,
9    clippy::dbg_macro,
10    clippy::decimal_literal_representation,
11    clippy::default_numeric_fallback,
12    clippy::else_if_without_else,
13    clippy::exhaustive_enums,
14    clippy::exhaustive_structs,
15    clippy::exit,
16    clippy::expect_used,
17    clippy::filetype_is_file,
18    clippy::float_arithmetic,
19    clippy::float_cmp_const,
20    clippy::get_unwrap,
21    clippy::if_then_some_else_none,
22    clippy::indexing_slicing,
23    clippy::integer_arithmetic,
24    clippy::integer_division,
25    clippy::let_underscore_must_use,
26    clippy::lossy_float_literal,
27    clippy::map_err_ignore,
28    clippy::mem_forget,
29    clippy::missing_docs_in_private_items,
30    clippy::modulo_arithmetic,
31    clippy::multiple_inherent_impl,
32    clippy::panic,
33    clippy::panic_in_result_fn,
34    clippy::pattern_type_mismatch,
35    clippy::print_stderr,
36    clippy::print_stdout,
37    clippy::rc_buffer,
38    clippy::rest_pat_in_fully_bound_structs,
39    clippy::str_to_string,
40    clippy::string_add,
41    clippy::string_to_string,
42    clippy::todo,
43    clippy::unimplemented,
44    clippy::unnecessary_self_imports,
45    clippy::unneeded_field_pattern,
46    clippy::unreachable,
47    clippy::unwrap_in_result,
48    clippy::unwrap_used,
49    clippy::use_debug,
50    clippy::verbose_file_reads,
51    clippy::wildcard_enum_match_arm
52)]
53// reasonable rustc lints
54#![warn(
55    elided_lifetimes_in_paths,
56    explicit_outlives_requirements,
57    macro_use_extern_crate,
58    meta_variable_misuse,
59    missing_abi,
60    missing_copy_implementations,
61    missing_debug_implementations,
62    missing_docs,
63    non_ascii_idents,
64    noop_method_call,
65    semicolon_in_expressions_from_macros,
66    trivial_casts,
67    trivial_numeric_casts,
68    unreachable_pub,
69    unsafe_op_in_unsafe_fn,
70    unused_crate_dependencies,
71    unused_extern_crates,
72    unused_import_braces,
73    unused_lifetimes,
74    unused_qualifications,
75    unused_results,
76    variant_size_differences
77)]
78// reasonable rustdoc lints
79#![warn(
80    rustdoc::missing_crate_level_docs,
81    rustdoc::missing_doc_code_examples,
82    rustdoc::private_doc_tests,
83    rustdoc::invalid_html_tags
84)]
85
86//! [![crates.io]](https://crates.io/crates/existential)
87//! [![github]](https://github.com/steffahn/existential)
88//! [![MIT / Apache 2.0 licensed]](https://github.com/steffahn/existential#License)
89//!
90//! [Existential types](https://wiki.haskell.org/Existential_type) in Rust, offering existential
91//! quantification over lifetimes, but as a library. This works because Rust has
92//! [parametricity](https://en.wikipedia.org/wiki/Parametricity) for generic lifetime arguments.
93//!
94//! _TODO: this crate is still undocumented._
95//!
96//! [github]: https://img.shields.io/badge/github-steffahn/existential-yellowgreen.svg
97//! [crates.io]: https://img.shields.io/crates/v/existential.svg?maxAge=86400
98//! [MIT / Apache 2.0 licensed]: https://img.shields.io/crates/l/existential.svg?maxAge=2592000
99//! [docs.rs]: https://docs.rs/existential/badge.svg
100
101use core::{
102    marker::PhantomData,
103    mem::{self, ManuallyDrop},
104};
105
106pub trait TyConFor<'a> {
107    type Applied;
108}
109
110pub type Apply<'a, C> = <C as TyConFor<'a>>::Applied;
111
112pub trait TyCon: for<'a> TyConFor<'a> {}
113impl<C: ?Sized> TyCon for C where C: for<'a> TyConFor<'a> {}
114
115pub struct Existential<'lower_bound, C>
116where
117    C: TyCon,
118{
119    marker: PhantomData<&'lower_bound ()>,
120    inner: Apply<'lower_bound, C>,
121}
122
123impl<'lower_bound, C> Existential<'lower_bound, C>
124where
125    C: TyCon,
126{
127    pub fn new<'a: 'lower_bound>(inner: Apply<'a, C>) -> Existential<'lower_bound, C> {
128        let inner = ManuallyDrop::new(inner);
129        unsafe {
130            Self {
131                marker: PhantomData,
132                inner: mem::transmute_copy::<Apply<'a, C>, Apply<'lower_bound, C>>(&inner),
133            }
134        }
135    }
136    pub fn with<'s, F, O>(&'s self, f: F) -> O
137    where
138        F: for<'a> FnOnce(&'s Apply<'a, C>, PhantomData<&'lower_bound &'a ()>) -> O,
139    {
140        f(&self.inner, PhantomData)
141    }
142    pub fn with_mut<'s, F, O>(&'s mut self, f: F) -> O
143    where
144        F: for<'a> FnOnce(&'s mut Apply<'a, C>, PhantomData<&'lower_bound &'a ()>) -> O,
145    {
146        f(&mut self.inner, PhantomData)
147    }
148    pub fn with_owned<F, O>(self, f: F) -> O
149    where
150        F: for<'a> FnOnce(Apply<'a, C>, PhantomData<&'lower_bound &'a ()>) -> O,
151    {
152        f(self.inner, PhantomData)
153    }
154}