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}