1use 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
29const WORD_BITS: u32 = u64::BITS;
31
32#[derive(Copy, Clone)]
34struct Field {
35 column: ColumnRef,
36 depth: u8,
37}
38
39pub 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 pub fn new(spec: &MirrorSpec, wanted: u64, rate: Rate) -> Result<Declared, Diagnostic> {
58 Self::scoped(spec, wanted, rate, None)
59 }
60
61 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 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 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 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 pub fn row_of(&self, key: u64) -> Option<u32> {
122 self.space.row_of(key)
123 }
124
125 pub fn key_of(&self, row: u32) -> Option<u64> {
127 self.space.key_of(row)
128 }
129
130 #[inline]
132 pub fn get<T: Cell>(&self, field: usize, row: u32) -> Option<T> {
133 let f = (*self.fields.get(field)?)?;
134 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
146pub struct Writer {
148 mirror: String,
150 space_name: String,
152 scopes: Vec<Vec<u8>>,
154 writing: u64,
156 fields: u64,
157 space: Option<KeySpaceRef>,
158 rows: Option<ColumnWriter>,
159 columns: Vec<Option<ColumnWriter>>,
161}
162
163impl Writer {
164 fn open(w: Write) -> Writer {
165 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 space: unsafe { KeySpaceRef::new(w.space as *const _) },
181 rows: open(w.rows),
182 columns,
183 }
184 }
185
186 pub fn mirror(&self) -> &str {
188 &self.mirror
189 }
190
191 pub fn scopes(&self) -> &[Vec<u8>] {
193 &self.scopes
194 }
195
196 pub fn writing(&self, i: usize) -> bool {
198 i >= yog_mirror::SCOPE_PACES || self.writing >> i & 1 == 1
199 }
200
201 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 #[inline]
228 pub fn wants(&self, field: usize) -> bool {
229 self.fields >> field & 1 == 1
230 }
231
232 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 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 #[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
258unsafe 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 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;