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, 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
27const WORD_BITS: u32 = u64::BITS;
29
30#[derive(Copy, Clone)]
32struct Field {
33 column: ColumnRef,
34 depth: u8,
35}
36
37pub 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 pub fn new(spec: &MirrorSpec, wanted: u64, rate: Rate) -> Result<Declared, Diagnostic> {
56 Self::scoped(spec, wanted, rate, None)
57 }
58
59 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 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 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 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 pub fn row_of(&self, key: u64) -> Option<u32> {
120 self.space.row_of(key)
121 }
122
123 pub fn key_of(&self, row: u32) -> Option<u64> {
125 self.space.key_of(row)
126 }
127
128 #[inline]
130 pub fn get<T: Cell>(&self, field: usize, row: u32) -> Option<T> {
131 let f = (*self.fields.get(field)?)?;
132 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
144pub struct Writer {
146 mirror: String,
148 space_name: String,
150 scopes: Vec<Vec<u8>>,
152 fields: u64,
153 space: Option<KeySpaceRef>,
154 rows: Option<ColumnWriter>,
155 columns: Vec<Option<ColumnWriter>>,
157}
158
159impl Writer {
160 fn open(w: Write) -> Writer {
161 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 space: unsafe { KeySpaceRef::new(w.space as *const _) },
176 rows: open(w.rows),
177 columns,
178 }
179 }
180
181 pub fn mirror(&self) -> &str {
183 &self.mirror
184 }
185
186 pub fn scopes(&self) -> &[Vec<u8>] {
188 &self.scopes
189 }
190
191 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 #[inline]
218 pub fn wants(&self, field: usize) -> bool {
219 self.fields >> field & 1 == 1
220 }
221
222 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 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 #[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
248unsafe 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 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;