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