give up on ORM style models

This commit is contained in:
Aiden McClelland
2021-03-22 15:49:51 -06:00
parent 5a83aa5926
commit 9fd80fae58
2 changed files with 57 additions and 256 deletions

View File

@@ -1,7 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::future::Future;
use std::io::Error as IOError; use std::io::Error as IOError;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
@@ -956,276 +957,82 @@ impl Default for Locker {
} }
} }
pub trait ModelData: Send + Sync { pub struct ModelData<T: Serialize + for<'de> Deserialize<'de>>(T);
type Inner; impl<T: Serialize + for<'de> Deserialize<'de>> Deref for ModelData<T> {
fn apply< type Target = T;
'a, fn deref(&self) -> &Self::Target {
F: FnOnce(&mut Self::Inner) -> ResFut + Send + Sync + 'a, &self.0
ResFut: Future<Output = Res> + Send + Sync + 'a,
Res: Send + Sync + 'a,
>(
&'a mut self,
f: F,
) -> BoxFuture<'a, Res>;
}
pub enum Never {}
impl ModelData for Never {
type Inner = Never;
fn apply<
'a,
F: FnOnce(&mut Self::Inner) -> ResFut + 'a,
ResFut: Future<Output = Res> + 'a,
Res: 'a,
>(
&'a mut self,
_: F,
) -> BoxFuture<'a, Res> {
match *self {}
} }
} }
pub enum GenericModelData<T: Serialize + for<'de> Deserialize<'de>, Parent: ModelData> { pub struct ModelDataMut<T: Serialize + for<'de> Deserialize<'de>> {
Uninitialized(Vec<ChildHooks<T>>), original: Value,
Ref( current: T,
Arc<dyn Fn(&mut Parent::Inner) -> &mut T + Send + Sync>,
Arc<Mutex<Parent>>,
),
Owned(Box<T>),
}
impl<T: Serialize + for<'de> Deserialize<'de>, Parent: ModelData> GenericModelData<T, Parent> {
pub fn is_initialized(&self) -> bool {
match self {
GenericModelData::Uninitialized(_) => false,
_ => true,
}
}
async fn apply<
F: FnOnce(&mut T) -> ResFut + Send + Sync,
ResFut: Future<Output = Res> + Send + Sync,
Res: Send + Sync,
>(
&mut self,
f: F,
) -> Res {
match self {
GenericModelData::Owned(data) => f(data).await,
GenericModelData::Ref(g, parent) => parent.lock().await.apply(|t| f(g(t))).await,
_ => panic!("uninitialized"),
}
}
}
impl<T: Serialize + for<'de> Deserialize<'de> + Send + Sync, Parent: ModelData> ModelData
for GenericModelData<T, Parent>
{
type Inner = T;
fn apply<
'a,
F: FnOnce(&mut Self::Inner) -> ResFut + Send + Sync + 'a,
ResFut: Future<Output = Res> + Send + Sync + 'a,
Res: Send + Sync + 'a,
>(
&'a mut self,
f: F,
) -> BoxFuture<'a, Res> {
self.apply(f).boxed()
}
}
pub struct ChildHooks<T> {
init_parent: Box<dyn for<'a> FnOnce(&'a mut T) -> BoxFuture<'a, ()> + Send + Sync>,
save_data: Box<
dyn Fn() -> BoxFuture<'static, Result<Vec<(JsonPointer, Value)>, serde_json::Error>>
+ Send
+ Sync,
>,
}
impl<T> ChildHooks<T> {
async fn init_parent(self, parent: &mut T) {
(self.init_parent)(parent).await
}
async fn save_data(&self) -> Result<Vec<(JsonPointer, Value)>, serde_json::Error> {
(self.save_data)().await
}
}
pub trait Model {
type Data: ModelData;
}
impl Model for Never {
type Data = Never;
}
pub struct GenericModel<T: Serialize + for<'de> Deserialize<'de>, Parent: ModelData> {
data: Arc<Mutex<GenericModelData<T, Parent>>>,
ptr: JsonPointer, ptr: JsonPointer,
} }
impl<T, Parent> GenericModel<T, Parent> impl<T: Serialize + for<'de> Deserialize<'de>> ModelDataMut<T> {
pub async fn save<Tx: Checkpoint>(self, tx: &mut Tx) -> Result<(), Error> {
let current = serde_json::to_value(&self.current)?;
let mut diff = DiffPatch(json_patch::diff(&self.original, &current));
let target = tx.get_value(&self.ptr, None).await?;
diff.rebase(&DiffPatch(json_patch::diff(&self.original, &target)));
diff.0.prepend(&self.ptr);
tx.apply(diff);
Ok(())
}
}
impl<T: Serialize + for<'de> Deserialize<'de>> Deref for ModelDataMut<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.current
}
}
impl<T: Serialize + for<'de> Deserialize<'de>> DerefMut for ModelDataMut<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.current
}
}
pub struct Model<T: Serialize + for<'de> Deserialize<'de>> {
ptr: JsonPointer,
phantom: PhantomData<T>,
}
impl<T> Model<T>
where where
T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static, T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static,
Parent: ModelData + 'static,
{ {
pub fn new(ptr: JsonPointer) -> Self { pub fn new(ptr: JsonPointer) -> Self {
Self { Self {
data: Arc::new(Mutex::new(GenericModelData::Uninitialized(Vec::new()))),
ptr, ptr,
phantom: PhantomData,
} }
} }
// locks
async fn fetch<Tx: Checkpoint>(&mut self, tx: &mut Tx) -> Result<(), Error> {
let mut data = self.data.lock().await;
if let GenericModelData::Uninitialized(children) = &mut *data {
let mut a: Box<T> = tx.get(&self.ptr, LockType::None).await?;
for child in std::mem::replace(children, Vec::new()) {
child.init_parent(&mut a).await;
}
*data = GenericModelData::Owned(a);
}
Ok(())
}
pub async fn lock<Tx: Checkpoint>(&self, tx: &mut Tx, lock: LockType) { pub async fn lock<Tx: Checkpoint>(&self, tx: &mut Tx, lock: LockType) {
tx.lock(&self.ptr, lock).await tx.lock(&self.ptr, lock).await
} }
// locks pub async fn get<Tx: Checkpoint>(&self, tx: &mut Tx) -> Result<ModelData<T>, Error> {
pub async fn peek< Ok(ModelData(tx.get(&self.ptr, LockType::Read).await?))
Tx: Checkpoint,
F: FnOnce(&T) -> ResFut + Send + Sync,
ResFut: Future<Output = Res> + Send + Sync,
Res: Send + Sync,
>(
&mut self,
tx: &mut Tx,
f: F,
) -> Result<Res, Error> {
self.lock(tx, LockType::Read).await;
self.fetch(tx).await?;
Ok(self.data.lock().await.apply(|t| f(t)).await)
} }
// locks pub async fn get_mut<Tx: Checkpoint>(&mut self, tx: &mut Tx) -> Result<ModelDataMut<T>, Error> {
pub async fn apply<
Tx: Checkpoint,
F: FnOnce(&mut T) -> ResFut + Send + Sync,
ResFut: Future<Output = Res> + Send + Sync,
Res: Send + Sync,
>(
&mut self,
tx: &mut Tx,
f: F,
) -> Result<Res, Error> {
self.lock(tx, LockType::Write).await; self.lock(tx, LockType::Write).await;
self.fetch(tx).await?; let original = tx.get_value(&self.ptr, None).await?;
Ok(self.data.lock().await.apply(f).await) let current = serde_json::from_value(original.clone())?;
Ok(ModelDataMut {
original,
current,
ptr: self.ptr.clone(),
})
} }
// locks pub fn child<C: Serialize + for<'de> Deserialize<'de>>(&self, index: &str) -> Model<C> {
pub async fn child<C, F, S, V>( let mut ptr = self.ptr.clone();
&mut self, ptr.push_end(index);
path: &JsonPointer<S, V>, Model {
f: F,
) -> GenericModel<C, GenericModelData<T, Parent>>
where
C: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static,
F: Fn(&mut T) -> &mut C + Send + Sync + 'static,
S: AsRef<str>,
V: SegList,
for<'v> &'v V: IntoIterator<Item = &'v json_ptr::PtrSegment>,
{
let arc_f = Arc::new(f);
let ptr = self.ptr.clone() + path;
let mut data_ref = self.data.lock().await;
let data = if let GenericModelData::Uninitialized(children) = &mut *data_ref {
let data = Arc::new(Mutex::new(GenericModelData::Uninitialized(Vec::new())));
let init_parent_data = data.clone();
let parent_data = self.data.clone();
let save_data_data = data.clone();
let save_data_ptr = ptr.clone();
children.push(ChildHooks {
init_parent: Box::new(move |parent| {
async move {
let mut data_ref = init_parent_data.lock().await;
let self_data = std::mem::replace(
&mut *data_ref,
GenericModelData::Uninitialized(Vec::new()),
);
match self_data {
GenericModelData::Owned(t) => *arc_f(parent) = *t,
GenericModelData::Uninitialized(children) => {
for child in children {
child.init_parent(arc_f(parent)).await; // TODO: can probably parallelize
}
}
_ => (),
}
*data_ref = GenericModelData::Ref(arc_f, parent_data);
}
.boxed()
}),
save_data: Box::new(move || {
let ptr = save_data_ptr.clone();
let data = save_data_data.clone();
async move {
let mut data_ref = data.lock().await;
if let GenericModelData::Uninitialized(children) = &mut *data_ref {
let mut res = Vec::new();
for child in children {
res.append(&mut child.save_data().await?)
}
Ok(res)
} else {
Ok(vec![(
ptr, ptr,
data_ref phantom: PhantomData,
.apply(|t| futures::future::ready(serde_json::to_value(t)))
.await?,
)])
} }
} }
.boxed()
}),
});
data
} else {
Arc::new(Mutex::new(GenericModelData::Ref(
arc_f.clone(),
self.data.clone(),
)))
};
GenericModel { data, ptr }
}
/// locks
pub async fn save<Tx: Checkpoint>(&mut self, tx: &mut Tx) -> Result<(), Error> {
let mut data_ref = self.data.lock().await;
for (ptr, value) in if let GenericModelData::Uninitialized(children) = &mut *data_ref {
let mut res = Vec::new();
for child in children {
res.append(&mut child.save_data().await?)
}
res
} else {
vec![(
self.ptr.clone(),
data_ref
.apply(|t| futures::future::ready(serde_json::to_value(t)))
.await?,
)]
} {
tx.put_value(&ptr, &value).await?;
}
Ok(())
}
}
impl<T, Parent> Model for GenericModel<T, Parent>
where
T: Serialize + for<'de> Deserialize<'de> + Send + Sync,
Parent: ModelData,
{
type Data = GenericModelData<T, Parent>;
} }

View File

@@ -15,10 +15,7 @@ pub struct Sample {
b: Child, b: Child,
} }
pub struct SampleModel<Parent: Model = Never>(GenericModel<Sample, Parent::Data>); pub struct SampleModel(Model<Sample>);
impl<Parent: Model> Model for SampleModel<Parent> {
type Data = GenericModelData<Sample, Parent::Data>;
}
#[derive(Debug, serde::Deserialize, serde::Serialize)] #[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct Child { pub struct Child {
@@ -26,7 +23,4 @@ pub struct Child {
b: usize, b: usize,
} }
pub struct ChildModel<Parent: Model = Never>(GenericModel<Child, Parent::Data>); pub struct ChildModel(Model<Child>);
impl<Parent: Model> Model for ChildModel<Parent> {
type Data = GenericModelData<Sample, Parent::Data>;
}