Skip to main content

pumpkin_core/propagation/
store.rs

1use std::fmt::Debug;
2use std::marker::PhantomData;
3use std::ops::Index;
4use std::ops::IndexMut;
5
6use super::Propagator;
7use super::PropagatorId;
8use crate::containers::KeyedVec;
9use crate::containers::Slot;
10use crate::engine::DebugDyn;
11
12/// A central store for propagators.
13#[derive(Default, Clone)]
14pub(crate) struct PropagatorStore {
15    propagators: KeyedVec<PropagatorId, Box<dyn Propagator>>,
16}
17
18/// A typed wrapper around a propagator id that allows retrieving concrete propagators instead of
19/// type-erased instances `Box<dyn Propagator>`.
20#[derive(Debug, PartialEq, Eq, Hash)]
21pub struct PropagatorHandle<P> {
22    id: PropagatorId,
23    propagator: PhantomData<P>,
24}
25
26impl<P> PropagatorHandle<P> {
27    pub(crate) fn new(propagator_id: PropagatorId) -> PropagatorHandle<P> {
28        Self {
29            id: propagator_id,
30            propagator: PhantomData,
31        }
32    }
33
34    /// Get the type-erased [`PropagatorId`] of the propagator.
35    pub(crate) fn propagator_id(self) -> PropagatorId {
36        self.id
37    }
38}
39
40impl<P> Clone for PropagatorHandle<P> {
41    fn clone(&self) -> Self {
42        *self
43    }
44}
45
46impl<P> Copy for PropagatorHandle<P> {}
47
48impl PropagatorStore {
49    pub(crate) fn num_propagators(&self) -> usize {
50        self.propagators.len()
51    }
52
53    pub(crate) fn iter_propagators(&self) -> impl Iterator<Item = &dyn Propagator> + '_ {
54        self.propagators.iter().map(|b| b.as_ref())
55    }
56
57    pub(crate) fn iter_propagators_mut(
58        &mut self,
59    ) -> impl Iterator<Item = &mut Box<dyn Propagator>> + '_ {
60        self.propagators.iter_mut()
61    }
62
63    pub(crate) fn new_propagator<P>(&mut self) -> NewPropagatorSlot<'_, P> {
64        NewPropagatorSlot {
65            underlying_slot: self.propagators.new_slot(),
66            propagator_type: PhantomData,
67        }
68    }
69
70    /// Get an exclusive reference to the propagator identified by the given handle.
71    ///
72    /// For more info, see [`Self::get_propagator`].
73    pub(crate) fn get_propagator<P: Propagator>(&self, handle: PropagatorHandle<P>) -> Option<&P> {
74        self[handle.id].downcast_ref()
75    }
76
77    /// Get an exclusive reference to the propagator identified by the given handle.
78    ///
79    /// For more info, see [`Self::get_propagator`].
80    pub(crate) fn get_propagator_mut<P: Propagator>(
81        &mut self,
82        handle: PropagatorHandle<P>,
83    ) -> Option<&mut P> {
84        self[handle.id].downcast_mut()
85    }
86
87    /// Get the given [`PropagatorId`] as a handle if the ID points to a propagator of type `P`.
88    pub(crate) fn as_propagator_handle<P: Propagator>(
89        &self,
90        propagator_id: PropagatorId,
91    ) -> Option<PropagatorHandle<P>> {
92        if self[propagator_id].is::<P>() {
93            Some(PropagatorHandle {
94                id: propagator_id,
95                propagator: PhantomData,
96            })
97        } else {
98            None
99        }
100    }
101}
102
103impl Index<PropagatorId> for PropagatorStore {
104    type Output = dyn Propagator;
105
106    fn index(&self, index: PropagatorId) -> &Self::Output {
107        self.propagators[index].as_ref()
108    }
109}
110
111impl IndexMut<PropagatorId> for PropagatorStore {
112    fn index_mut(&mut self, index: PropagatorId) -> &mut Self::Output {
113        self.propagators[index].as_mut()
114    }
115}
116
117/// Wrapper around a [`Slot`] that provides a strongly typed [`PropagatorHandle`] instead of a
118/// type-erased [`PropagatorId`].
119pub(crate) struct NewPropagatorSlot<'a, P> {
120    underlying_slot: Slot<'a, PropagatorId, Box<dyn Propagator>>,
121    propagator_type: PhantomData<P>,
122}
123
124impl<P: Propagator + 'static> NewPropagatorSlot<'_, P> {
125    /// The handle corresponding to this slot.
126    pub(crate) fn key(&self) -> PropagatorHandle<P> {
127        PropagatorHandle {
128            id: self.underlying_slot.key(),
129            propagator: PhantomData,
130        }
131    }
132
133    /// Put a propagator into the slot.
134    pub(crate) fn populate(self, propagator: P) -> PropagatorHandle<P> {
135        PropagatorHandle {
136            id: self.underlying_slot.populate(Box::new(propagator)),
137            propagator: PhantomData,
138        }
139    }
140}
141
142impl Debug for PropagatorStore {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        let propagators: Vec<_> = self
145            .propagators
146            .iter()
147            .map(|_| DebugDyn::from("Propagator"))
148            .collect();
149
150        write!(f, "{propagators:?}")
151    }
152}