v9/
column.rs

1//! Columns and their extractions.
2
3use crate::event::*;
4use crate::prelude_lib::*;
5use std::hint::unreachable_unchecked;
6use crate::linkage::LiftColumn;
7
8#[derive(Debug)]
9#[derive(serde::Serialize, serde::Deserialize)]
10#[serde(transparent)]
11pub struct Column<M: TableMarker, T> {
12    #[serde(skip)]
13    pub table_marker: M,
14    // NB: This is unsafe to access. You could make the columns have different lengths.
15    #[doc(hidden)]
16    pub data: Vec<T>,
17}
18impl<M: TableMarker, T> Default for Column<M, T> {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23impl<M: TableMarker, T> Column<M, T> {
24    pub fn new() -> Self {
25        Column {
26            table_marker: Default::default(),
27            data: vec![],
28        }
29    }
30    #[inline(always)] pub fn data(&self) -> &Vec<T> { &self.data }
31    #[inline(always)] pub unsafe fn data_mut(&mut self) -> &mut Vec<T> { &mut self.data }
32    #[inline(always)] pub fn set_data(&mut self, d: Vec<T>) { self.data = d }
33}
34
35pub type FastEdit<'a, C> = FastEditColumn<
36    'a,
37    <C as LiftColumn>::M,
38    <C as LiftColumn>::T,
39>;
40
41pub struct ReadColumn<'a, M: TableMarker, T> {
42    pub col: &'a Column<M, T>,
43}
44pub struct FastEditColumn<'a, M: TableMarker, T> {
45    col: &'a mut Column<M, T>,
46}
47/// You can change the values in this column, but not the length.
48/// Changes may be logged. Because of this, you must access items in increasing order.
49// FIXME: Maybe we could work around this. What if we saved a copy of the original to the log?
50// HashSet?
51pub struct EditColumn<'a, M: TableMarker, T>
52where
53    T: Clone,
54{
55    #[doc(hidden)]
56    pub col: &'a mut Column<M, T>,
57    must_log: bool,
58    log: &'a mut Vec<(Id<M>, T)>,
59}
60pub struct WriteColumn<'a, M: TableMarker, T> {
61    pub col: MutButRef<'a, Column<M, T>>,
62}
63
64#[cold]
65fn disordered_column_access() -> ! {
66    panic!("disordered column access")
67}
68impl<'a, 'b, I, M: TableMarker, T> Index<I> for ReadColumn<'a, M, T>
69where
70    I: 'b + Check<M = M>,
71{
72    type Output = T;
73    fn index(&self, i: I) -> &T {
74        unsafe {
75            let i = i.check_from_len(PhantomData, self.col.data.len());
76            self.col.data.get_unchecked(i.to_usize())
77        }
78    }
79}
80impl<'a, 'b, I, M: TableMarker, T> Index<I> for FastEditColumn<'a, M, T>
81where
82    I: 'b + Check<M = M>,
83{
84    type Output = T;
85    fn index(&self, i: I) -> &T {
86        unsafe {
87            let i = i.check_from_len(PhantomData, self.col.data.len());
88            self.col.data.get_unchecked(i.to_usize())
89        }
90    }
91}
92impl<'a, 'b, I, M: TableMarker, T> IndexMut<I> for FastEditColumn<'a, M, T>
93where
94    I: 'b + Check<M = M>,
95{
96    fn index_mut(&mut self, i: I) -> &mut T {
97        unsafe {
98            let i = i.check_from_len(PhantomData, self.col.data.len());
99            self.col.data.get_unchecked_mut(i.to_usize())
100        }
101    }
102}
103impl<'a, 'b, I, M: TableMarker, T> Index<I> for EditColumn<'a, M, T>
104where
105    T: Clone,
106    I: 'b + Check<M = M>,
107{
108    type Output = T;
109    fn index(&self, i: I) -> &T {
110        unsafe {
111            let i = i.check_from_len(PhantomData, self.col.data.len());
112            if let Some((prev, dude)) = self.log.last() {
113                match i.uncheck().cmp(prev) {
114                    Ordering::Less => disordered_column_access(),
115                    Ordering::Equal => dude,
116                    Ordering::Greater => self.col.data.get_unchecked(i.to_usize()),
117                }
118            } else {
119                self.col.data.get_unchecked(i.to_usize())
120            }
121        }
122    }
123}
124impl<'a, 'b, I, M: TableMarker, T> IndexMut<I> for EditColumn<'a, M, T>
125where
126    T: Clone,
127    I: 'b + Check<M = M>,
128{
129    fn index_mut(&mut self, i: I) -> &mut T {
130        unsafe {
131            let i = i.check_from_len(PhantomData, self.col.data.len());
132            let i = i.uncheck();
133            if !self.must_log {
134                return self.col.data.get_unchecked_mut(i.to_usize());
135            }
136            let prev = self.log.last().map(|(i, _)| i);
137            let prev = prev.map(|prev| i.cmp(prev));
138            let prev = prev.unwrap_or(Ordering::Greater);
139            match prev {
140                Ordering::Less => disordered_column_access(),
141                Ordering::Equal => (),
142                Ordering::Greater => {
143                    let val = self.col.data.get_unchecked(i.to_usize()).clone();
144                    self.log.push((i, val))
145                }
146            }
147            if let Some((_i, v)) = self.log.last_mut() {
148                v
149            } else {
150                unreachable_unchecked()
151            }
152        }
153    }
154}
155impl<'a, 'b, M: TableMarker, T, I> Index<I> for WriteColumn<'a, M, T>
156where
157    I: 'b + Check<M = M>,
158{
159    type Output = T;
160    fn index(&self, i: I) -> &T {
161        unsafe {
162            let i = i.check_from_len(PhantomData, self.col.data.len());
163            self.col.data.get_unchecked(i.to_usize())
164        }
165    }
166}
167// WriteColumn is append-only, so IndexMut is not provided.
168
169impl<'a, M: TableMarker, T> WriteColumn<'a, M, T> {
170    pub fn borrow(&self) -> ReadColumn<M, T> {
171        ReadColumn { col: &*self.col }
172    }
173}
174impl<'a, M: TableMarker, T> EditColumn<'a, M, T>
175where
176    T: Clone,
177{
178    pub fn borrow(&self) -> ReadColumn<M, T> {
179        assert!(self.log.is_empty());
180        ReadColumn { col: &*self.col }
181    }
182}
183
184unsafe impl<'a, M, T: Send + Sync> ExtractOwned for ReadColumn<'a, M, T>
185where
186    M: TableMarker,
187    T: 'static,
188{
189    type Ty = Column<M, T>;
190    const ACC: Access = Access::Read;
191    unsafe fn extract(_universe: &Universe, rez: &mut Rez) -> Self {
192        let obj: &'static dyn Any = rez.take_ref();
193        ReadColumn {
194            col: obj.downcast_ref().unwrap(),
195        }
196    }
197}
198unsafe impl<'a, M, T: Send + Sync> ExtractOwned for FastEditColumn<'a, M, T>
199where
200    M: TableMarker,
201    T: 'static,
202{
203    type Ty = Column<M, T>;
204    const ACC: Access = Access::Write;
205    unsafe fn extract(universe: &Universe, rez: &mut Rez) -> Self {
206        let obj: &'static mut dyn Any = rez.take_mut();
207        assert!(!universe.is_tracked::<Edited<M, T>>(), "FastEditColumn used on a tracked column");
208        FastEditColumn {
209            col: obj.downcast_mut().unwrap(),
210        }
211    }
212}
213#[doc(hidden)]
214pub struct EditColumnOwned<'a, M, T>
215where
216    M: TableMarker,
217{
218    col: &'a mut Column<M, T>,
219    must_log: bool,
220    log: Vec<(Id<M>, T)>,
221}
222unsafe impl<'a, M, T> Extract for EditColumn<'a, M, T>
223where
224    M: TableMarker,
225    T: 'static + Send + Sync,
226    T: Clone,
227{
228    fn each_resource(f: &mut dyn FnMut(TypeId, Access)) {
229        f(TypeId::of::<Column<M, T>>(), Access::Write)
230    }
231    type Owned = EditColumnOwned<'a, M, T>;
232    unsafe fn extract(universe: &Universe, rez: &mut Rez) -> Self::Owned {
233        let col: &mut Column<M, T> = rez.take_mut_downcast();
234        let must_log = universe.is_tracked::<Edited<M, T>>();
235        let log = vec![];
236        EditColumnOwned { col, must_log, log }
237    }
238    unsafe fn convert(_universe: &Universe, owned: *mut Self::Owned) -> Self {
239        let EditColumnOwned { col, must_log, log } = &mut *owned;
240        EditColumn { col, must_log: *must_log, log }
241    }
242    type Cleanup = EditColumnCleanup<M, T>;
243}
244#[doc(hidden)]
245pub struct EditColumnCleanup<M: TableMarker, T> {
246    must_log: bool,
247    log: Vec<(Id<M>, T)>,
248}
249unsafe impl<'a, M, T> Cleaner<EditColumn<'a, M, T>> for EditColumnCleanup<M, T>
250where
251    M: TableMarker,
252    T: 'static + Send + Sync,
253    T: Clone,
254    // or `EditColumn<>: Extract`?
255{
256    fn pre_cleanup(eco: EditColumnOwned<'a, M, T>, _universe: &Universe) -> Self {
257        Self {
258            must_log: eco.must_log,
259            log: eco.log,
260        }
261    }
262    fn post_cleanup(self, universe: &Universe) {
263        if !self.must_log || self.log.is_empty() {
264            return;
265        }
266        let log = universe.with(move |col: &Column<M, T>| {
267            let col = col as *const _;
268            let mut ev = Edited { col, new: self.log };
269            universe.submit_event(&mut ev);
270            ev.new
271        });
272        universe.with_mut(move |col: &mut Column<M, T>| {
273            for (id, new) in log.into_iter() {
274                col.data[id.0.to_usize()] = new;
275            }
276        });
277    }
278}
279unsafe impl<'a, M, T> ExtractOwned for WriteColumn<'a, M, T>
280where
281    M: TableMarker,
282    T: 'static + Send + Sync,
283{
284    type Ty = Column<M, T>;
285    const ACC: Access = Access::Write;
286    unsafe fn extract(_universe: &Universe, rez: &mut Rez) -> Self {
287        WriteColumn {
288            col: MutButRef::new(rez.take_mut_downcast()),
289        }
290    }
291}
292
293pub unsafe trait ColumnInfo<M: TableMarker> {
294    fn len(&self) -> usize;
295    fn is_empty(&self) -> bool {
296        self.len() == 0
297    }
298}
299unsafe impl<M: TableMarker, T> ColumnInfo<M> for Column<M, T> {
300    fn len(&self) -> usize {
301        self.data.len()
302    }
303}
304unsafe impl<'a, M: TableMarker, T> ColumnInfo<M> for ReadColumn<'a, M, T> {
305    fn len(&self) -> usize {
306        self.col.data.len()
307    }
308}
309unsafe impl<'a, M: TableMarker, T: Clone> ColumnInfo<M> for EditColumn<'a, M, T> {
310    fn len(&self) -> usize {
311        self.col.data.len()
312    }
313}
314unsafe impl<'a, M: TableMarker, T> ColumnInfo<M> for WriteColumn<'a, M, T> {
315    fn len(&self) -> usize {
316        self.col.data.len()
317    }
318}