moore_common/arenas.rs
1// Copyright (c) 2016-2021 Fabian Schuiki
2
3//! Multi-type arena allocation
4
5#![deny(missing_docs)]
6
7use std::borrow::Cow;
8pub use typed_arena::Arena as TypedArena;
9
10/// Allocates values.
11pub trait Alloc<'a, 't, T: 't> {
12 /// Allocate a value of type `T`.
13 fn alloc(&'a self, value: T) -> &'t mut T;
14}
15
16impl<'z, 'a, 'p: 'a, 't, T: 't> Alloc<'z, 't, T> for &'p dyn Alloc<'a, 't, T> {
17 fn alloc(&'z self, value: T) -> &'t mut T {
18 Alloc::alloc(*self, value)
19 }
20}
21
22/// Allocates values into itself.
23///
24/// This is merely a marker trait that you should not implement yourself. It is
25/// implemented automatically on anything that supports `Alloc<'a, 'a, T>` for
26/// any `'a`. The allocated values have the same lifetime as `&self`.
27pub trait AllocSelf<T>: for<'a> Alloc<'a, 'a, T> {}
28
29// Implement `AllocSelf` for anything that supports the proper `Alloc`.
30impl<T, A> AllocSelf<T> for A where A: for<'a> Alloc<'a, 'a, T> {}
31
32/// Allocates values into some arena.
33///
34/// This is merely a marker trait that you should not implement yourself. It is
35/// implemented automatically on anything that supports `Alloc<'a, 't, T>` for
36/// any `'a`. The allocated values have the lifetime `'t`.
37pub trait AllocInto<'t, T: 't>: for<'a> Alloc<'a, 't, T> {}
38
39// Implement `AllocInto` for anything that supports the proper `Alloc`.
40impl<'t, T, A> AllocInto<'t, T> for A
41where
42 T: 't,
43 A: for<'a> Alloc<'a, 't, T>,
44{
45}
46
47/// Allocates values implementing `ToOwned`.
48///
49/// This is merely a marker trait that you should not implement yourself. It is
50/// implemented automatically on anything that supports `Alloc`.
51pub trait AllocOwned<'a, 't, T: ToOwned + ?Sized + 't> {
52 /// Allocate a value of type `T: ToOwned` into this arena.
53 ///
54 /// This function differs from `Alloc::alloc` in that it takes `T::Owned`
55 /// and returns `&T`.
56 fn alloc_owned(&'a self, value: <T as ToOwned>::Owned) -> &'t T;
57
58 /// Conditionally allocate a value of type `Cow<T>`.
59 ///
60 /// If the value is `Cow::Owned`, allocates and returns a reference to it;
61 /// if it is `Cow::Borrowed`, returns the reference without allocation. This
62 /// requires that the borrow in `Cow` has the same lifetime as the allocated
63 /// reference will have, as indicated by the type `Cow<'t, T> -> &'t T`. Use
64 /// `force_alloc` if you don't have such a lifetime guarantee.
65 fn maybe_alloc(&'a self, value: Cow<'t, T>) -> &'t T {
66 match value {
67 Cow::Borrowed(x) => x,
68 Cow::Owned(x) => self.alloc_owned(x),
69 }
70 }
71
72 /// Forcefully allocate a value of type `Cow<T>`.
73 ///
74 /// Regardless of whether the value is `Cow::Owned` or `Cow::Borrowed`, it
75 /// is converted to the owned value via `ToOwned::into_owned()` and
76 /// allocated. This function is useful if you have no guarantee that the
77 /// lifetime of the borrow in `Cow` has the same lifetime as the allocated
78 /// reference, as indicated by the type `Cow<T> -> &'t T'. Use `maybe_alloc`
79 /// if you do have such a lifetime guarantee.
80 fn force_alloc(&'a self, value: Cow<T>) -> &'t T {
81 self.alloc_owned(value.into_owned())
82 }
83}
84
85// Implement `AllocOwned` for anything that supports the proper `Alloc` and for
86// any types that implement `ToOwned` with `Owned` equal to the type.
87impl<'a, 't, T: ToOwned<Owned = T> + 't> AllocOwned<'a, 't, T> for dyn Alloc<'a, 't, T> {
88 fn alloc_owned(&'a self, value: T) -> &'t T {
89 self.alloc(value)
90 }
91}
92
93/// Allocates values implementing `ToOwned` into itself.
94///
95/// This is merely a marker trait that you should not implement yourself. It is
96/// implemented automatically on anything that supports `AllocOwned<'a, 'a, T>`
97/// for any `'a`. The allocated values have the same lifetime as `&self`.
98pub trait AllocOwnedSelf<T: ToOwned + ?Sized>: for<'a> AllocOwned<'a, 'a, T> {}
99
100// Implement `AllocOwnedSelf` for anything that supports the proper
101// `AllocOwned`.
102impl<T, A> AllocOwnedSelf<T> for A
103where
104 T: ToOwned + ?Sized,
105 A: for<'a> AllocOwned<'a, 'a, T>,
106{
107}
108
109/// Allocates values implementing `ToOwned` into some arena.
110///
111/// This is merely a marker trait that you should not implement yourself. It is
112/// implemented automatically on anything that supports `AllocOwned<'a, 't, T>`
113/// for any `'a`. The allocated values have the lifetime `'t`.
114pub trait AllocOwnedInto<'t, T: ToOwned + ?Sized + 't>: for<'a> AllocOwned<'a, 't, T> {}
115
116// Implement `AllocOwnedInto` for anything that supports the proper
117// `AllocOwned`.
118impl<'t, T, A> AllocOwnedInto<'t, T> for A
119where
120 T: ToOwned + ?Sized + 't,
121 A: for<'a> AllocOwned<'a, 't, T>,
122{
123}
124
125/// Generate a collection of arenas for different types.
126#[macro_export]
127macro_rules! make_arenas {
128 ($(#[$arena_attr:meta])* pub struct $arena_name:ident { $($name:ident: $type:ty,)* }) => {
129 make_arenas!{ IMPL $($arena_attr),*; $arena_name; []; $($name: $type,)* }
130 };
131
132 ($(#[$arena_attr:meta])* pub struct $arena_name:ident<$($lt:tt),+> { $($name:ident: $type:ty,)* }) => {
133 make_arenas!{ IMPL $($arena_attr),*; $arena_name; [$($lt),+]; $($name: $type,)* }
134 };
135
136 (IMPL $($arena_attr:meta),*; $arena_name:ident; [$($lt:tt),*]; $($name:ident: $type:ty,)*) => {
137 $(#[$arena_attr])*
138 #[allow(missing_docs)]
139 pub struct $arena_name<$($lt),*> {
140 dummy: std::marker::PhantomData<($(&$lt ()),*)>,
141 $(pub $name: $crate::arenas::TypedArena<$type>,)*
142 }
143
144 make_arenas!(STRUCT_IMPL $arena_name; [$($lt),*]; $($name: $type,)*);
145 };
146
147 (STRUCT_IMPL $arena_name:ident; [$($lt:tt),*]; $($name:ident: $type:ty,)*) => {
148 impl<$($lt),*> $arena_name<$($lt),*> {
149 /// Create a new arena.
150 pub fn new() -> $arena_name<$($lt),*> {
151 $arena_name {
152 dummy: Default::default(),
153 $($name: $crate::arenas::TypedArena::new(),)*
154 }
155 }
156 }
157
158 impl<$($lt),*> Default for $arena_name<$($lt),*> {
159 fn default() -> $arena_name<$($lt),*> {
160 $arena_name::new()
161 }
162 }
163
164 make_arenas!(TRAIT_IMPL $arena_name; [$($lt),*]; $($name: $type,)*);
165 };
166
167 (TRAIT_IMPL $arena_name:ident; [$($lt:tt),*]; $name:ident: $type:ty, $($tail_name:ident: $tail_type:ty,)*) => {
168 impl<'a, $($lt),*> $crate::arenas::Alloc<'a, 'a, $type> for $arena_name<$($lt),*> where $($lt: 'a),* {
169 fn alloc(&'a self, value: $type) -> &'a mut $type {
170 self.$name.alloc(value)
171 }
172 }
173
174 make_arenas!(TRAIT_IMPL $arena_name; [$($lt),*]; $($tail_name: $tail_type,)*);
175 };
176
177 (TRAIT_IMPL $arena_name:ident; [$($lt:tt),*];) => {}
178}