eips/options.rs
1/*
2 * Copyright (C) 2025 taylor.fish <contact@taylor.fish>
3 *
4 * This file is part of Eips.
5 *
6 * Eips is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Eips is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with Eips. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20//! Options for [`Eips`].
21
22#[cfg(doc)]
23use crate::Eips;
24use crate::node::Node;
25use core::marker::PhantomData;
26use integral_constant::{Bool, Constant, Usize};
27
28mod arena {
29 pub use fixed_typed_arena::options::*;
30}
31
32mod skippy {
33 pub use skippy::options::*;
34}
35
36mod detail {
37 use super::*;
38
39 pub trait ListFanoutPriv: skippy::Fanout {}
40
41 pub trait ChunkSizePriv: Constant<usize> {
42 type ForArena<T>: arena::ChunkSize<T>;
43 }
44
45 pub trait SupportsMovePriv {
46 type Packed<Id, Opt: EipsOptions>: crate::node::Packed<Id, Opt>;
47 }
48}
49
50pub(crate) use detail::*;
51
52/// Trait bound on [`EipsOptions::ListFanout`].
53pub trait ListFanout: ListFanoutPriv {}
54
55impl<const N: usize> ListFanout for Usize<N> {}
56impl<const N: usize> ListFanoutPriv for Usize<N> {}
57
58/// Trait bound on [`EipsOptions::ChunkSize`].
59pub trait ChunkSize: ChunkSizePriv {}
60
61impl<const N: usize> ChunkSize for Usize<N> {}
62impl<const N: usize> ChunkSizePriv for Usize<N> {
63 type ForArena<T> = Self;
64}
65
66/// Trait bound on [`EipsOptions::SupportsMove`].
67pub trait SupportsMove: SupportsMovePriv {}
68
69impl SupportsMove for Bool<false> {}
70impl SupportsMove for Bool<true> {}
71
72impl SupportsMovePriv for Bool<false> {
73 type Packed<Id, Opt: EipsOptions> = crate::node::MinimalPacked;
74}
75
76impl SupportsMovePriv for Bool<true> {
77 type Packed<Id, Opt: EipsOptions> = crate::node::FullPacked<Id, Opt>;
78}
79
80pub(crate) type Packed<Id, Opt> =
81 <<Opt as EipsOptions>::SupportsMove as SupportsMovePriv>::Packed<Id, Opt>;
82
83mod sealed {
84 pub trait Sealed: Sized {}
85}
86
87/// Options trait for [`Eips`].
88///
89/// This is a sealed trait; use the [`Options`] type, which implements this
90/// trait.
91pub trait EipsOptions: sealed::Sealed {
92 /// Whether move operations are supported. If true, you can call
93 /// [`Eips::mv`] to move an item to another position.
94 ///
95 /// The value of this option should be the same for all clients in a
96 /// distributed system. A client that supports move operations cannot
97 /// communicate with one that doesn't.
98 ///
99 /// More memory is used when this option is enabled. Each list item
100 /// (including deleted elements) will use 8 to 14 bytes of additional
101 /// memory, depending on the size and alignment of the ID type (due to
102 /// padding).
103 ///
104 /// *Default:* true
105 type SupportsMove: SupportsMove;
106
107 /// Eips internally uses tree-like structures implemented using linked
108 /// lists. This option controls the maximum number of children each
109 /// internal node can have.
110 ///
111 /// Increasing this value decreases the amount of auxiliary memory used,
112 /// but also decreases performance.
113 ///
114 /// Specifically, the amount of auxiliary memory used by Eips is
115 /// Θ(*[h]*/*f* ),[^1] where *f* is this value ([`Self::ListFanout`]).
116 ///
117 /// Thus, increasing this value decreases the amount of auxiliary memory.
118 /// However, it also increases the runtime of many operations by a constant
119 /// factor, since many operations are O( *f* ) (with respect to *f* only),
120 /// such as [`Eips::remote_get`], which is O( *f* log *[h]*).
121 ///
122 /// *Default:* 12
123 ///
124 /// [^1]: With respect to *[h]* and *f* only.
125 ///
126 /// [h]: Eips#mathematical-variables
127 type ListFanout: ListFanout;
128
129 /// Instead of allocating small regions of memory individually, Eips
130 /// allocates larger chunks and uses them to serve small allocations. This
131 /// option controls how many small allocations can be served by each chunk.
132 ///
133 /// Increasing this value decreases the amount of a certain category of
134 /// auxiliary memory, but also increases the amount of a different
135 /// category. However, this usually results in a net decrease.
136 ///
137 /// Specifically, the amount of auxiliary memory used by Eips is
138 /// worst-case[^1] Θ(*[h]*/*c*) + Θ(*c*),[^2] where *c* is this value
139 /// ([`Self::ChunkSize`]).
140 ///
141 /// Thus, increasing this value decreases the Θ(*[h]*/*c*) portion of the
142 /// auxiliary memory, but increases the Θ(*c*) portion. However, as *h*
143 /// grows, larger values of *c* typically result in a net decrease of
144 /// memory.
145 ///
146 /// *Default:* 32
147 ///
148 /// [^1]: And average-case. Best-case is Θ(*[h]*/*c*) only.
149 ///
150 /// [^2]: With respect to *[h]* and *c* only.
151 ///
152 /// [h]: Eips#mathematical-variables
153 type ChunkSize: ChunkSize;
154}
155
156/// Options for [`Eips`].
157///
158/// This type implements [`EipsOptions`]. Const parameters correspond to
159/// associated types in [`EipsOptions`] as follows; see those associated types
160/// for documentation:
161///
162/// Const parameter | Associated type
163/// ---------------- | ------------------------------
164/// `SUPPORTS_MOVE` | [`EipsOptions::SupportsMove`]
165/// `LIST_FANOUT` | [`EipsOptions::ListFanout`]
166/// `CHUNK_SIZE` | [`EipsOptions::ChunkSize`]
167#[rustfmt::skip]
168pub type Options<
169 const SUPPORTS_MOVE: bool = true,
170 const LIST_FANOUT: usize = 12,
171 const CHUNK_SIZE: usize = 32,
172> = TypedOptions<
173 Bool<SUPPORTS_MOVE>,
174 Usize<LIST_FANOUT>,
175 Usize<CHUNK_SIZE>,
176>;
177
178/// Like [`Options`], but uses types instead of const parameters.
179///
180/// [`Options`] is actually a type alias of this type.
181#[allow(clippy::type_complexity)]
182#[rustfmt::skip]
183pub struct TypedOptions<
184 SupportsMove = Bool<true>,
185 ListFanout = Usize<12>,
186 ChunkSize = Usize<32>,
187>(PhantomData<fn() -> (
188 SupportsMove,
189 ListFanout,
190 ChunkSize,
191)>);
192
193#[rustfmt::skip]
194impl<
195 SupportsMove,
196 ListFanout,
197 ChunkSize,
198> sealed::Sealed for TypedOptions<
199 SupportsMove,
200 ListFanout,
201 ChunkSize,
202> {}
203
204#[rustfmt::skip]
205impl<
206 SupportsMove: self::SupportsMove,
207 ListFanout: self::ListFanout,
208 ChunkSize: self::ChunkSize,
209> EipsOptions for TypedOptions<
210 SupportsMove,
211 ListFanout,
212 ChunkSize,
213> {
214 type SupportsMove = SupportsMove;
215 type ListFanout = ListFanout;
216 type ChunkSize = ChunkSize;
217}
218
219type GetChunkSize<Opt> = <Opt as EipsOptions>::ChunkSize;
220type ArenaChunkSize<Opt, T> =
221 <GetChunkSize<Opt> as ChunkSizePriv>::ForArena<T>;
222
223pub(crate) type NodeAllocOptions<Id, Opt> = arena::TypedOptions<
224 /* ChunkSize */ ArenaChunkSize<Opt, Node<Id, Opt>>,
225 /* SupportsPositions */ Bool<true>,
226 /* Mutable */ Bool<false>,
227>;
228
229pub(crate) type PosMapOptions<Id, Opt> = skippy::TypedOptions<
230 /* SizeType */ usize,
231 /* StoreKeys */ Bool<false>,
232 /* Fanout */ <Opt as EipsOptions>::ListFanout,
233 /* Align */ Node<Id, Opt>,
234>;
235
236pub(crate) type SiblingSetOptions<Id, Opt> = skippy::TypedOptions<
237 /* SizeType */ skippy::NoSize,
238 /* StoreKeys */ Bool<true>,
239 /* Fanout */ <Opt as EipsOptions>::ListFanout,
240 /* Align */ Node<Id, Opt>,
241>;
242
243pub(crate) const fn chunk_size<Opt: EipsOptions>() -> usize {
244 Opt::ChunkSize::VALUE
245}