Skip to main content

yog_api/
mirror.rs

1//! Mirrors (`docs/design/bus.md`, "Mirrors"): data read every tick kept in
2//! shared memory. A mod declares the fields it reads ([`Declared`]: read in
3//! place, released on drop) or provides a mirror ([`Registry::provide_mirror`]:
4//! its writer is called when fields are due, with only those). Usually
5//! through `#[yog_mirror]`, which generates both sides typed.
6
7use std::os::raw::c_void;
8
9use yog_abi::{YogBytes, YogReply, YogStatus, YogStr, status};
10use yog_data::Diagnostic;
11use yog_event::Message;
12use yog_event::mirror::{Declare, Key, Keys, Provide, Release, Write};
13use yog_mirror::{Bits, ColumnRef, ColumnWriter, KeySpaceRef};
14use yog_sync::Arc;
15
16pub use yog_mirror::{Cell, FieldSpec, Kind, MirrorSpec, Rate};
17
18use crate::registry::{Registry, guard};
19
20mod host;
21mod typed;
22pub use host::{Blocks, Entities, Players};
23pub use typed::{Mirror, MirrorWriter, Mirrored, Row, RowWriter};
24pub use yog_event::mirror::BlockScope;
25pub use yog_mirror::host as host_tables;
26
27/// Bits a word of a row bitmap holds.
28const WORD_BITS: u32 = u64::BITS;
29
30/// A declaration's field: its column, how many parents up its space is.
31#[derive(Copy, Clone)]
32struct Field {
33    column: ColumnRef,
34    depth: u8,
35}
36
37/// Fields of a mirror asked for: written at the rate asked while this
38/// lives, read in place; dropped, what only it asked for stops.
39pub struct Declared {
40    id: u32,
41    space: KeySpaceRef,
42    rows: ColumnRef,
43    fields: Vec<Option<Field>>,
44}
45
46fn no_runtime() -> Diagnostic {
47    Diagnostic::error(
48        yog_ids::mirror_problem::FAILED,
49        "no one answers mirrors here",
50    )
51}
52
53impl Declared {
54    /// Asks for `wanted` fields of `spec` (a bit each, in field order) at `rate`.
55    pub fn new(spec: &MirrorSpec, wanted: u64, rate: Rate) -> Result<Declared, Diagnostic> {
56        Self::scoped(spec, wanted, rate, None)
57    }
58
59    /// [`Declared::new`] covering `scope` only (the mirror's scope type as
60    /// Yog Data: a `BlockScope`…).
61    pub fn scoped(
62        spec: &MirrorSpec,
63        wanted: u64,
64        rate: Rate,
65        scope: Option<Vec<u8>>,
66    ) -> Result<Declared, Diagnostic> {
67        let request = Declare {
68            spec: spec.clone(),
69            wanted,
70            rate,
71            scope: scope.map(|bytes| yog_event::mirror::Scope { bytes }),
72        };
73        let reply = crate::call(&request).ok_or_else(no_runtime)?;
74        let d = match (reply.declaration, reply.problem) {
75            (Some(d), _) => d,
76            (None, problem) => return Err(problem.unwrap_or_else(no_runtime)),
77        };
78        // SAFETY: the runtime keeps what a declaration points at until it's released.
79        let (space, rows) = unsafe {
80            (
81                KeySpaceRef::new(d.space as *const _),
82                ColumnRef::new(d.rows as *const _),
83            )
84        };
85        let fields = d
86            .fields
87            .iter()
88            .map(|f| {
89                let f = (*f)?;
90                // SAFETY: as above.
91                let column = unsafe { ColumnRef::new(f.column as *const _) }?;
92                Some(Field {
93                    column,
94                    depth: f.depth,
95                })
96            })
97            .collect();
98        match (space, rows) {
99            (Some(space), Some(rows)) => Ok(Declared {
100                id: d.id,
101                space,
102                rows,
103                fields,
104            }),
105            _ => Err(no_runtime()),
106        }
107    }
108
109    /// The rows its provider fills that hold a key now.
110    pub fn rows(&self) -> impl Iterator<Item = u32> + '_ {
111        let words = self.space.rows().div_ceil(WORD_BITS);
112        (0..words).flat_map(move |w| {
113            let both = self.rows.word(w) & self.space.live_word(w);
114            Bits(both).map(move |b| w * WORD_BITS + b)
115        })
116    }
117
118    /// `key`'s row.
119    pub fn row_of(&self, key: u64) -> Option<u32> {
120        self.space.row_of(key)
121    }
122
123    /// Row `row`'s key.
124    pub fn key_of(&self, row: u32) -> Option<u64> {
125        self.space.key_of(row)
126    }
127
128    /// Field `field`'s value at row `row` (`None`: not asked for, no row).
129    #[inline]
130    pub fn get<T: Cell>(&self, field: usize, row: u32) -> Option<T> {
131        let f = (*self.fields.get(field)?)?;
132        // A parent space's fact: the row's key there, its row there.
133        let (_, row) = self.space.up(row, f.depth)?;
134        f.column.get(row)
135    }
136}
137
138impl Drop for Declared {
139    fn drop(&mut self) {
140        crate::call(&Release { id: self.id });
141    }
142}
143
144/// A provider's turn: the fields due, written for the rows it fills.
145pub struct Writer {
146    /// The mirror's address (a family member's ends in its parameter).
147    mirror: String,
148    /// Its key space's name.
149    space_name: String,
150    /// What its declarations asked it to cover (its scope type's frames).
151    scopes: Vec<Vec<u8>>,
152    fields: u64,
153    space: Option<KeySpaceRef>,
154    rows: Option<ColumnWriter>,
155    /// The due fields' columns open for writing, by field.
156    columns: Vec<Option<ColumnWriter>>,
157}
158
159impl Writer {
160    fn open(w: Write) -> Writer {
161        // SAFETY: the runtime's addresses, alive through this turn.
162        let open = |c: u64| unsafe { ColumnRef::new(c as *const _) }.map(|c| c.write());
163        let due = (0..u64::BITS as usize).filter(|i| w.fields >> i & 1 == 1);
164        let mut columns: Vec<Option<ColumnWriter>> = Vec::new();
165        for (i, c) in due.zip(&w.columns) {
166            columns.resize_with(columns.len().max(i + 1), || None);
167            columns[i] = open(*c);
168        }
169        Writer {
170            mirror: w.mirror,
171            space_name: w.space_name,
172            scopes: w.scopes.into_iter().map(|s| s.bytes).collect(),
173            fields: w.fields,
174            // SAFETY: as above.
175            space: unsafe { KeySpaceRef::new(w.space as *const _) },
176            rows: open(w.rows),
177            columns,
178        }
179    }
180
181    /// The mirror's address.
182    pub fn mirror(&self) -> &str {
183        &self.mirror
184    }
185
186    /// What the declarations asked it to cover, each its scope type's frame.
187    pub fn scopes(&self) -> &[Vec<u8>] {
188        &self.scopes
189    }
190
191    /// Makes its key space's keys `live` (each with its parent key): the
192    /// new ones put, the others taken — for a mod's own key space.
193    pub fn keep_keys(&mut self, live: &[(u64, Option<u64>)]) {
194        let Some(space) = self.space else { return };
195        let wanted: std::collections::HashSet<u64> = live.iter().map(|(k, _)| *k).collect();
196        let take: Vec<u64> = space
197            .live()
198            .map(|(_, k)| k)
199            .filter(|k| !wanted.contains(k))
200            .collect();
201        let put: Vec<Key> = live
202            .iter()
203            .filter(|(k, _)| space.row_of(*k).is_none())
204            .map(|&(key, parent)| Key { key, parent })
205            .collect();
206        if put.is_empty() && take.is_empty() {
207            return;
208        }
209        crate::call(&Keys {
210            space: self.space_name.clone(),
211            put,
212            take,
213        });
214    }
215
216    /// Whether field `field` is due (someone asked for it now).
217    #[inline]
218    pub fn wants(&self, field: usize) -> bool {
219        self.fields >> field & 1 == 1
220    }
221
222    /// `key`'s row (a key its space hasn't got has none: nothing to write).
223    pub fn row(&mut self, key: u64) -> Option<u32> {
224        let row = self.space?.row_of(key)?;
225        if let Some(rows) = &mut self.rows {
226            rows.set_bit(row, true);
227        }
228        Some(row)
229    }
230
231    /// Row `row` no longer filled by this mirror.
232    pub fn leave(&mut self, row: u32) {
233        if let Some(rows) = &mut self.rows {
234            rows.set_bit(row, false);
235        }
236    }
237
238    /// Sets field `field` at `row` to what `value` gives — called only when
239    /// the field is due.
240    #[inline]
241    pub fn set<T: Cell>(&mut self, field: usize, row: u32, value: impl FnOnce() -> T) {
242        if let Some(Some(w)) = self.columns.get_mut(field) {
243            w.set(row, value());
244        }
245    }
246}
247
248/// The bus's handler for a mirror's writer `ud`.
249unsafe extern "C" fn on_write<F: Fn(&mut Writer) + Send + Sync>(
250    ud: *mut c_void,
251    payload: YogBytes,
252    _reply: *const YogReply,
253) -> YogStatus {
254    let f = unsafe { &*(ud as *const F) };
255    let Some(w) = Write::from_bytes(unsafe { payload.as_slice() }) else {
256        return status::BAD_PAYLOAD;
257    };
258    let mut writer = Writer::open(w);
259    guard((), || f(&mut writer));
260    status::OK
261}
262
263impl Registry {
264    /// Provides mirror `spec`: `write` fills what's due each time it is.
265    pub fn provide_mirror(
266        &mut self,
267        spec: &MirrorSpec,
268        write: impl Fn(&mut Writer) + Send + Sync + 'static,
269    ) -> bool {
270        self.providing_mirror(spec, false, Arc::new(write))
271    }
272
273    pub(crate) fn providing_mirror<F: Fn(&mut Writer) + Send + Sync + 'static>(
274        &mut self,
275        spec: &MirrorSpec,
276        family: bool,
277        write: Arc<F>,
278    ) -> bool {
279        let bus = unsafe { &*self.api().bus };
280        let ud = Arc::into_raw(write).cast_mut().cast::<c_void>();
281        let st = unsafe {
282            let at = (bus.resolve)(bus.ctx, YogStr::from_str(&spec.name));
283            (bus.provide)(bus.ctx, at, ud, on_write::<F>)
284        };
285        if st != status::OK {
286            crate::error!("{}: someone provides it already", spec.name);
287            return false;
288        }
289        let problem = self.call(&Provide {
290            spec: spec.clone(),
291            host: false,
292            family,
293        });
294        match problem.flatten() {
295            Some(p) => {
296                crate::error!("{}: {p}", spec.name);
297                false
298            }
299            None => true,
300        }
301    }
302}
303
304#[cfg(test)]
305mod tests;