use std::marker::PhantomData;
use yog_data::{Diagnostic, Schema};
use yog_ids::{sep, service_mirror};
use yog_sync::Arc;
use super::{Cell, Declared, FieldSpec, MirrorSpec, Rate, Writer};
use crate::registry::Registry;
pub trait Mirror: Sized + 'static {
const NAME: &'static str;
const OWNER: Option<&'static str>;
const SPACE: &'static str;
const ALL: u64;
const FAMILY: bool = false;
type View<'a>: From<Row<'a, Self>>;
type Writer<'w>: From<RowWriter<'w, Self>>;
fn fields() -> Vec<FieldSpec>;
fn read(row: &Row<'_, Self>) -> Self;
fn write(&self, row: &mut RowWriter<'_, Self>);
fn address() -> String {
let owner = Self::OWNER.unwrap_or_else(crate::mod_id);
format!(
"{}{owner}{}{}",
service_mirror::DOMAIN,
sep::PATH,
Self::NAME
)
}
fn spec() -> MirrorSpec {
MirrorSpec {
name: Self::address(),
space: Self::SPACE.to_owned(),
fields: Self::fields(),
}
}
fn declare(fields: u64, rate: Rate) -> Result<Mirrored<Self>, Diagnostic> {
Ok(Mirrored {
declared: Declared::new(&Self::spec(), fields, rate)?,
_mirror: PhantomData,
})
}
fn declare_in<S: Schema>(
member: &str,
scope: Option<&S>,
fields: u64,
rate: Rate,
) -> Result<Mirrored<Self>, Diagnostic> {
let mut spec = Self::spec();
spec.name = format!("{}{}{member}", spec.name, sep::PATH);
spec.space = format!("{}{}{member}", spec.space, sep::PATH);
let scope = scope.map(yog_data::frame::to_frame);
Ok(Mirrored {
declared: Declared::scoped(&spec, fields, rate, scope)?,
_mirror: PhantomData,
})
}
}
pub struct Mirrored<M: Mirror> {
declared: Declared,
_mirror: PhantomData<M>,
}
impl<M: Mirror> Mirrored<M> {
pub fn iter(&self) -> impl Iterator<Item = M::View<'_>> {
self.declared
.rows()
.map(|row| Row::new(&self.declared, row).into())
}
pub fn get(&self, key: u64) -> Option<M::View<'_>> {
Some(Row::new(&self.declared, self.declared.row_of(key)?).into())
}
pub fn declared(&self) -> &Declared {
&self.declared
}
}
pub struct Row<'a, M> {
declared: &'a Declared,
row: u32,
_mirror: PhantomData<M>,
}
impl<'a, M> Row<'a, M> {
fn new(declared: &'a Declared, row: u32) -> Self {
Row {
declared,
row,
_mirror: PhantomData,
}
}
pub fn row(&self) -> u32 {
self.row
}
pub fn key(&self) -> Option<u64> {
self.declared.key_of(self.row)
}
#[inline]
pub fn field<T: Cell>(&self, field: usize) -> T {
self.declared.get(field, self.row).unwrap_or_default()
}
}
pub struct RowWriter<'w, M> {
writer: &'w mut Writer,
row: u32,
_mirror: PhantomData<M>,
}
impl<M> RowWriter<'_, M> {
pub fn row(&self) -> u32 {
self.row
}
#[inline]
pub fn set<T: Cell>(&mut self, field: usize, value: impl FnOnce() -> T) {
if self.writer.wants(field) {
self.writer.set(field, self.row, value);
}
}
}
pub struct MirrorWriter<'w, M> {
writer: &'w mut Writer,
_mirror: PhantomData<M>,
}
impl<M: Mirror> MirrorWriter<'_, M> {
pub fn row(&mut self, key: u64) -> Option<M::Writer<'_>> {
let row = self.writer.row(key)?;
Some(
RowWriter {
writer: &mut *self.writer,
row,
_mirror: PhantomData,
}
.into(),
)
}
pub fn leave(&mut self, row: u32) {
self.writer.leave(row);
}
pub fn member(&self) -> Option<&str> {
let base = M::address();
self.writer
.mirror()
.strip_prefix(&base)?
.strip_prefix(sep::PATH)
}
pub fn scopes<S: Schema>(&self) -> impl Iterator<Item = S> + '_ {
self.writer
.scopes()
.iter()
.filter_map(|b| yog_data::frame::read_frame(b))
}
pub fn keep_keys(&mut self, live: &[(u64, Option<u64>)]) {
self.writer.keep_keys(live);
}
pub fn wants(&self, fields: u64) -> bool {
(0..u64::BITS as usize).any(|i| fields >> i & 1 == 1 && self.writer.wants(i))
}
}
impl Registry {
pub fn provide_mirror_of<M: Mirror>(
&mut self,
write: impl Fn(&mut MirrorWriter<'_, M>) + Send + Sync + 'static,
) -> bool {
let write = Arc::new(move |w: &mut Writer| {
write(&mut MirrorWriter {
writer: w,
_mirror: PhantomData,
})
});
self.providing_mirror(&M::spec(), M::FAMILY, write)
}
}