Skip to main content

yog_api/mirror/
typed.rs

1//! Typed mirrors: what `#[yog_mirror]` implements on a struct — its spec,
2//! a view a row (`ThreatView`: a getter a field) and a writer a row
3//! (`ThreatWriter`: a setter a field, given a closure called only when due).
4
5use std::marker::PhantomData;
6
7use yog_data::{Diagnostic, Schema};
8use yog_ids::{sep, service_mirror};
9use yog_sync::Arc;
10
11use super::{Cell, Clock, Declared, FieldSpec, MirrorSpec, Rate, Writer};
12use crate::registry::Registry;
13
14/// A mirror's row type (`#[yog_mirror]` implements it).
15pub trait Mirror: Sized + 'static {
16    /// Its name's last part: `yog:mirror/<mod>/<NAME>`.
17    const NAME: &'static str;
18    /// The mod providing it; `None`: this one.
19    const OWNER: Option<&'static str>;
20    /// Its key space (`yog_ids::key_space::*`).
21    const SPACE: &'static str;
22    /// Every field's bit.
23    const ALL: u64;
24    /// Its key space is a family (a member each parameter, `declare_in`).
25    const FAMILY: bool = false;
26    /// Whose ticks it's written after (the server's, unless it's a client's view).
27    const CLOCK: Clock = Clock::Server;
28    /// A row read.
29    type View<'a>: From<Row<'a, Self>>;
30    /// A row written.
31    type Writer<'w>: From<RowWriter<'w, Self>>;
32
33    /// Its fields, in order.
34    fn fields() -> Vec<FieldSpec>;
35
36    /// The whole row (a field not asked for reads as its default).
37    fn read(row: &Row<'_, Self>) -> Self;
38
39    /// Every due field of `row` set from `self`.
40    fn write(&self, row: &mut RowWriter<'_, Self>);
41
42    /// Its address.
43    fn address() -> String {
44        let owner = Self::OWNER.unwrap_or_else(crate::mod_id);
45        format!(
46            "{}{owner}{}{}",
47            service_mirror::DOMAIN,
48            sep::PATH,
49            Self::NAME
50        )
51    }
52
53    fn spec() -> MirrorSpec {
54        MirrorSpec {
55            name: Self::address(),
56            space: Self::SPACE.to_owned(),
57            fields: Self::fields(),
58            clock: Self::CLOCK,
59        }
60    }
61
62    /// Asks for `fields` (its bit consts or-ed) at `rate`.
63    fn declare(fields: u64, rate: Rate) -> Result<Mirrored<Self>, Diagnostic> {
64        Ok(Mirrored {
65            declared: Declared::new(&Self::spec(), fields, rate)?,
66            _mirror: PhantomData,
67        })
68    }
69
70    /// [`Mirror::declare`] covering `scope` (its scope type: a
71    /// `BlockScope`…) — a mirror that isn't a family's.
72    fn declare_scoped<S: Schema>(scope: &S, fields: u64, rate: Rate) -> Result<Mirrored<Self>, Diagnostic> {
73        let scope = Some(yog_data::frame::to_frame(scope));
74        Ok(Mirrored {
75            declared: Declared::scoped(&Self::spec(), fields, rate, scope)?,
76            _mirror: PhantomData,
77        })
78    }
79
80    /// [`Mirror::declare`] in member `member` of its family (a dimension:
81    /// `minecraft:overworld`), covering `scope` (its scope type: a
82    /// `BlockScope`…).
83    fn declare_in<S: Schema>(
84        member: &str,
85        scope: Option<&S>,
86        fields: u64,
87        rate: Rate,
88    ) -> Result<Mirrored<Self>, Diagnostic> {
89        let mut spec = Self::spec();
90        spec.name = format!("{}{}{member}", spec.name, sep::PATH);
91        spec.space = format!("{}{}{member}", spec.space, sep::PATH);
92        let scope = scope.map(yog_data::frame::to_frame);
93        Ok(Mirrored {
94            declared: Declared::scoped(&spec, fields, rate, scope)?,
95            _mirror: PhantomData,
96        })
97    }
98}
99
100/// A typed declaration: its rows read in place; dropped, released.
101pub struct Mirrored<M: Mirror> {
102    declared: Declared,
103    _mirror: PhantomData<M>,
104}
105
106impl<M: Mirror> Mirrored<M> {
107    /// Every row its provider fills.
108    pub fn iter(&self) -> impl Iterator<Item = M::View<'_>> {
109        self.declared
110            .rows()
111            .map(|row| Row::new(&self.declared, row).into())
112    }
113
114    /// `key`'s row.
115    pub fn get(&self, key: u64) -> Option<M::View<'_>> {
116        Some(Row::new(&self.declared, self.declared.row_of(key)?).into())
117    }
118
119    pub fn declared(&self) -> &Declared {
120        &self.declared
121    }
122}
123
124/// A row being read (what a generated view wraps).
125pub struct Row<'a, M> {
126    declared: &'a Declared,
127    row: u32,
128    _mirror: PhantomData<M>,
129}
130
131impl<'a, M> Row<'a, M> {
132    fn new(declared: &'a Declared, row: u32) -> Self {
133        Row {
134            declared,
135            row,
136            _mirror: PhantomData,
137        }
138    }
139
140    pub fn row(&self) -> u32 {
141        self.row
142    }
143
144    /// Its key.
145    pub fn key(&self) -> Option<u64> {
146        self.declared.key_of(self.row)
147    }
148
149    /// Field `field`'s value; its default when it wasn't asked for.
150    #[inline]
151    pub fn field<T: Cell>(&self, field: usize) -> T {
152        self.declared.get(field, self.row).unwrap_or_default()
153    }
154}
155
156/// A row being written (what a generated writer wraps).
157pub struct RowWriter<'w, M> {
158    writer: &'w mut Writer,
159    row: u32,
160    _mirror: PhantomData<M>,
161}
162
163impl<M> RowWriter<'_, M> {
164    pub fn row(&self) -> u32 {
165        self.row
166    }
167
168    /// Sets field `field` to what `value` gives, if it's due.
169    #[inline]
170    pub fn set<T: Cell>(&mut self, field: usize, value: impl FnOnce() -> T) {
171        if self.writer.wants(field) {
172            self.writer.set(field, self.row, value);
173        }
174    }
175}
176
177/// A typed provider's turn.
178pub struct MirrorWriter<'w, M> {
179    writer: &'w mut Writer,
180    _mirror: PhantomData<M>,
181}
182
183impl<M: Mirror> MirrorWriter<'_, M> {
184    /// `key`'s row to write, marked as filled; `None` when its space hasn't the key.
185    pub fn row(&mut self, key: u64) -> Option<M::Writer<'_>> {
186        let row = self.writer.row(key)?;
187        Some(
188            RowWriter {
189                writer: &mut *self.writer,
190                row,
191                _mirror: PhantomData,
192            }
193            .into(),
194        )
195    }
196
197    /// Row `row` no longer filled.
198    pub fn leave(&mut self, row: u32) {
199        self.writer.leave(row);
200    }
201
202    /// The family member written now (a dimension), when its space is a family's.
203    pub fn member(&self) -> Option<&str> {
204        let base = M::address();
205        self.writer
206            .mirror()
207            .strip_prefix(&base)?
208            .strip_prefix(sep::PATH)
209    }
210
211    /// What the declarations asked it to cover.
212    pub fn scopes<S: Schema>(&self) -> impl Iterator<Item = S> + '_ {
213        self.writer
214            .scopes()
215            .iter()
216            .filter_map(|b| yog_data::frame::read_frame(b))
217    }
218
219    /// The scopes due this turn (the others only kept as keys).
220    pub fn due_scopes<S: Schema>(&self) -> impl Iterator<Item = S> + '_ {
221        self.writer
222            .scopes()
223            .iter()
224            .enumerate()
225            .filter(|(i, _)| self.writer.writing(*i))
226            .filter_map(|(_, b)| yog_data::frame::read_frame(b))
227    }
228
229    /// Makes the key space's keys `live` (a mod's own key space).
230    pub fn keep_keys(&mut self, live: &[(u64, Option<u64>)]) {
231        self.writer.keep_keys(live);
232    }
233
234    /// Whether any of `fields` is due.
235    pub fn wants(&self, fields: u64) -> bool {
236        (0..u64::BITS as usize).any(|i| fields >> i & 1 == 1 && self.writer.wants(i))
237    }
238}
239
240impl Registry {
241    /// Provides mirror `M`: `write` fills what's due each time it is.
242    pub fn provide_mirror_of<M: Mirror>(
243        &mut self,
244        write: impl Fn(&mut MirrorWriter<'_, M>) + Send + Sync + 'static,
245    ) -> bool {
246        let write = Arc::new(move |w: &mut Writer| {
247            write(&mut MirrorWriter {
248                writer: w,
249                _mirror: PhantomData,
250            })
251        });
252        self.providing_mirror(&M::spec(), M::FAMILY, write)
253    }
254}