Skip to main content

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}