mirror of
https://github.com/Start9Labs/patch-db.git
synced 2026-03-26 02:11:54 +00:00
new and improved api
This commit is contained in:
@@ -34,8 +34,8 @@ pub fn build_model(item: &DeriveInput) -> TokenStream {
|
|||||||
Data::Enum(enum_ast) => build_model_enum(item, enum_ast, model_name),
|
Data::Enum(enum_ast) => build_model_enum(item, enum_ast, model_name),
|
||||||
_ => panic!("Models can only be created for Structs and Enums"),
|
_ => panic!("Models can only be created for Structs and Enums"),
|
||||||
};
|
};
|
||||||
if item.attrs.iter().any(|a| a.path.is_ident("macro_debug")) {
|
if let Some(dbg) = item.attrs.iter().find(|a| a.path.is_ident("macro_debug")) {
|
||||||
panic!("{}", res)
|
return Error::new_spanned(dbg, format!("{}", res)).to_compile_error();
|
||||||
} else {
|
} else {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@@ -167,8 +167,14 @@ fn separate_option(ty: &Type) -> (bool, &Type) {
|
|||||||
(false, ty)
|
(false, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_fns(children: &[ChildInfo]) -> TokenStream {
|
struct Fns {
|
||||||
let mut res = TokenStream::new();
|
impl_fns: TokenStream,
|
||||||
|
impl_mut_fns: TokenStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn impl_fns(children: &[ChildInfo]) -> Fns {
|
||||||
|
let mut impl_fns = TokenStream::new();
|
||||||
|
let mut impl_mut_fns = TokenStream::new();
|
||||||
for ChildInfo {
|
for ChildInfo {
|
||||||
vis,
|
vis,
|
||||||
name,
|
name,
|
||||||
@@ -206,14 +212,24 @@ fn impl_fns(children: &[ChildInfo]) -> TokenStream {
|
|||||||
a => a.clone(),
|
a => a.clone(),
|
||||||
};
|
};
|
||||||
let (optional, ty) = separate_option(ty);
|
let (optional, ty) = separate_option(ty);
|
||||||
let model_ty = if *has_model {
|
let (model_ty, model_mut_ty) = if *has_model {
|
||||||
quote_spanned! { name.span() =>
|
(
|
||||||
<#ty as patch_db::HasModel<'a>>::Model
|
quote_spanned! { name.span() =>
|
||||||
}
|
<#ty as patch_db::HasModel>::Model
|
||||||
|
},
|
||||||
|
quote_spanned! { name.span() =>
|
||||||
|
<<#ty as patch_db::HasModel>::Model as patch_db::Model>::Mut<'a>
|
||||||
|
},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
quote_spanned! { name.span() =>
|
(
|
||||||
patch_db::GenericModel::<'a, #ty>
|
quote_spanned! { name.span() =>
|
||||||
}
|
patch_db::GenericModel::<#ty>
|
||||||
|
},
|
||||||
|
quote_spanned! { name.span() =>
|
||||||
|
patch_db::GenericModelMut::<'a, #ty>
|
||||||
|
},
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let accessor = if let Some(accessor) = accessor {
|
let accessor = if let Some(accessor) = accessor {
|
||||||
quote! { [#accessor] }
|
quote! { [#accessor] }
|
||||||
@@ -221,20 +237,33 @@ fn impl_fns(children: &[ChildInfo]) -> TokenStream {
|
|||||||
quote! {}
|
quote! {}
|
||||||
};
|
};
|
||||||
if optional {
|
if optional {
|
||||||
res.extend(quote_spanned! { name.span() =>
|
impl_fns.extend(quote_spanned! { name.span() =>
|
||||||
#vis fn #name (&mut self) -> patch_db::OptionModel<'a, #model_ty> {
|
#vis fn #name (&self) -> patch_db::OptionModel<#model_ty> {
|
||||||
<patch_db::OptionModel::<'a, #model_ty> as patch_db::Model<'a>>::new(&mut self #accessor)
|
<patch_db::OptionModel::<#model_ty> as patch_db::Model>::new((&**self) #accessor .clone())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
impl_mut_fns.extend(quote_spanned! { name.span() =>
|
||||||
|
#vis fn #name (&self) -> patch_db::OptionModelMut<'a, #model_mut_ty> {
|
||||||
|
<patch_db::OptionModelMut::<'a, #model_mut_ty> as patch_db::ModelMut<'a>>::new(&mut (&mut **self) #accessor)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.extend(quote_spanned! { name.span() =>
|
impl_fns.extend(quote_spanned! { name.span() =>
|
||||||
#vis fn #name (&mut self) -> #model_ty {
|
#vis fn #name (&self) -> #model_ty {
|
||||||
<#model_ty as patch_db::Model<'a>>::new(&mut self #accessor)
|
<#model_ty as patch_db::Model>::new((&**self) #accessor .clone())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
impl_mut_fns.extend(quote_spanned! { name.span() =>
|
||||||
|
#vis fn #name (&mut self) -> #model_mut_ty {
|
||||||
|
<#model_mut_ty as patch_db::ModelMut<'a>>::new(&mut (&mut **self) #accessor)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res
|
Fns {
|
||||||
|
impl_fns,
|
||||||
|
impl_mut_fns,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_model_struct(
|
fn build_model_struct(
|
||||||
@@ -261,17 +290,47 @@ fn build_model_struct(
|
|||||||
let children = ChildInfo::from_fields(&serde_rename_all, &ast.fields);
|
let children = ChildInfo::from_fields(&serde_rename_all, &ast.fields);
|
||||||
let name = &base.ident;
|
let name = &base.ident;
|
||||||
let vis = &base.vis;
|
let vis = &base.vis;
|
||||||
let impl_fns = impl_fns(&children);
|
let Fns {
|
||||||
|
impl_fns,
|
||||||
|
impl_mut_fns,
|
||||||
|
} = impl_fns(&children);
|
||||||
quote! {
|
quote! {
|
||||||
impl<'a> patch_db::HasModel<'a> for #name {
|
impl patch_db::HasModel for #name {
|
||||||
type Model = #module_name::Model<'a>;
|
type Model = #module_name::Model;
|
||||||
}
|
}
|
||||||
#vis mod #module_name {
|
#vis mod #module_name {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Model<'a>(&'a mut patch_db::Value);
|
pub struct Model(patch_db::Value);
|
||||||
impl<'a> patch_db::Model<'a> for Model<'a> {
|
impl patch_db::Model for Model {
|
||||||
|
type T = #name;
|
||||||
|
type Mut<'a> = ModelMut<'a>;
|
||||||
|
fn new(value: patch_db::Value) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
fn into_inner(self) -> patch_db::Value {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ::core::ops::Deref for Model {
|
||||||
|
type Target = patch_db::Value;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ::core::ops::DerefMut for Model {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Model {
|
||||||
|
#impl_fns
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ModelMut<'a>(&'a mut patch_db::Value);
|
||||||
|
impl<'a> patch_db::ModelMut<'a> for ModelMut<'a> {
|
||||||
type T = #name;
|
type T = #name;
|
||||||
fn new(value: &'a mut patch_db::Value) -> Self {
|
fn new(value: &'a mut patch_db::Value) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
@@ -280,19 +339,19 @@ fn build_model_struct(
|
|||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> ::core::ops::Deref for Model<'a> {
|
impl<'a> ::core::ops::Deref for ModelMut<'a> {
|
||||||
type Target = patch_db::Value;
|
type Target = patch_db::Value;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&*self.0
|
&*self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> ::core::ops::DerefMut for Model<'a> {
|
impl<'a> ::core::ops::DerefMut for ModelMut<'a> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Model<'a> {
|
impl<'a> ModelMut<'a> {
|
||||||
#impl_fns
|
#impl_mut_fns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,11 +407,15 @@ fn build_model_enum(base: &DeriveInput, ast: &DataEnum, module_name: Option<Iden
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let mut model_variants = TokenStream::new();
|
let mut model_variants = TokenStream::new();
|
||||||
|
let mut mut_model_variants = TokenStream::new();
|
||||||
let mut decl_model_variants = TokenStream::new();
|
let mut decl_model_variants = TokenStream::new();
|
||||||
let mut into_inner = TokenStream::new();
|
let mut into_inner = TokenStream::new();
|
||||||
let mut deref = TokenStream::new();
|
let mut deref = TokenStream::new();
|
||||||
let mut deref_mut = TokenStream::new();
|
let mut deref_mut = TokenStream::new();
|
||||||
let impl_new = if let Some(Lit::Str(tag)) = serde_tag.remove("tag") {
|
let mut mut_into_inner = TokenStream::new();
|
||||||
|
let mut mut_deref = TokenStream::new();
|
||||||
|
let mut mut_deref_mut = TokenStream::new();
|
||||||
|
let (impl_new, impl_new_mut) = if let Some(Lit::Str(tag)) = serde_tag.remove("tag") {
|
||||||
children.push(ChildInfo {
|
children.push(ChildInfo {
|
||||||
vis: Visibility::Public(VisPublic {
|
vis: Visibility::Public(VisPublic {
|
||||||
pub_token: Pub::default(),
|
pub_token: Pub::default(),
|
||||||
@@ -367,62 +430,107 @@ fn build_model_enum(base: &DeriveInput, ast: &DataEnum, module_name: Option<Iden
|
|||||||
});
|
});
|
||||||
if let Some(Lit::Str(content)) = serde_tag.remove("content") {
|
if let Some(Lit::Str(content)) = serde_tag.remove("content") {
|
||||||
let mut tag_variants = TokenStream::new();
|
let mut tag_variants = TokenStream::new();
|
||||||
|
let mut tag_variants_mut = TokenStream::new();
|
||||||
for variant in &ast.variants {
|
for variant in &ast.variants {
|
||||||
let variant_name = &variant.ident;
|
let variant_name = &variant.ident;
|
||||||
let variant_model =
|
let variant_model =
|
||||||
Ident::new(&format!("{}Model", variant_name), variant_name.span());
|
Ident::new(&format!("{}Model", variant_name), variant_name.span());
|
||||||
|
let variant_model_mut =
|
||||||
|
Ident::new(&format!("{}ModelMut", variant_name), variant_name.span());
|
||||||
let variant_accessor =
|
let variant_accessor =
|
||||||
get_accessor(&serde_rename_all, &variant.attrs, variant_name);
|
get_accessor(&serde_rename_all, &variant.attrs, variant_name);
|
||||||
tag_variants.extend(quote_spanned! { variant_name.span() =>
|
tag_variants.extend(quote_spanned! { variant_name.span() =>
|
||||||
Some(#variant_accessor) => Model::#variant_name(#variant_model(&mut value[#content])),
|
Some(#variant_accessor) => Model::#variant_name(#variant_model(value[#content].clone())),
|
||||||
|
});
|
||||||
|
tag_variants_mut.extend(quote_spanned! { variant_name.span() =>
|
||||||
|
Some(#variant_accessor) => ModelMut::#variant_name(#variant_model_mut(&mut value[#content])),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
quote! {
|
(
|
||||||
match value[#tag].as_str() {
|
quote! {
|
||||||
#tag_variants
|
match value[#tag].as_str() {
|
||||||
_ => Model::Error(value),
|
#tag_variants
|
||||||
}
|
_ => Model::Error(value),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
quote! {
|
||||||
|
match value[#tag].as_str() {
|
||||||
|
#tag_variants_mut
|
||||||
|
_ => ModelMut::Error(value),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let mut tag_variants = TokenStream::new();
|
let mut tag_variants = TokenStream::new();
|
||||||
|
let mut tag_variants_mut = TokenStream::new();
|
||||||
for variant in &ast.variants {
|
for variant in &ast.variants {
|
||||||
let variant_name = &variant.ident;
|
let variant_name = &variant.ident;
|
||||||
let variant_model =
|
let variant_model =
|
||||||
Ident::new(&format!("{}Model", variant_name), variant_name.span());
|
Ident::new(&format!("{}Model", variant_name), variant_name.span());
|
||||||
|
let variant_model_mut =
|
||||||
|
Ident::new(&format!("{}ModelMut", variant_name), variant_name.span());
|
||||||
let variant_accessor =
|
let variant_accessor =
|
||||||
get_accessor(&serde_rename_all, &variant.attrs, variant_name);
|
get_accessor(&serde_rename_all, &variant.attrs, variant_name);
|
||||||
tag_variants.extend(quote_spanned! { variant_name.span() =>
|
tag_variants.extend(quote_spanned! { variant_name.span() =>
|
||||||
Some(#variant_accessor) => Model::#variant_name(#variant_model(value)),
|
Some(#variant_accessor) => Model::#variant_name(#variant_model(value)),
|
||||||
});
|
});
|
||||||
|
tag_variants_mut.extend(quote_spanned! { variant_name.span() =>
|
||||||
|
Some(#variant_accessor) => ModelMut::#variant_name(#variant_model_mut(value)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
quote! {
|
(
|
||||||
match value[#tag].as_str() {
|
quote! {
|
||||||
#tag_variants
|
match value[#tag].as_str() {
|
||||||
_ => Model::Error(value),
|
#tag_variants
|
||||||
}
|
_ => Model::Error(value),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
quote! {
|
||||||
|
match value[#tag].as_str() {
|
||||||
|
#tag_variants_mut
|
||||||
|
_ => ModelMut::Error(value),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut tag_variants = TokenStream::new();
|
let mut tag_variants = TokenStream::new();
|
||||||
|
let mut tag_variants_mut = TokenStream::new();
|
||||||
for variant in &ast.variants {
|
for variant in &ast.variants {
|
||||||
let variant_name = &variant.ident;
|
let variant_name = &variant.ident;
|
||||||
let variant_model = Ident::new(&format!("{}Model", variant_name), variant_name.span());
|
let variant_model = Ident::new(&format!("{}Model", variant_name), variant_name.span());
|
||||||
|
let variant_model_mut =
|
||||||
|
Ident::new(&format!("{}ModelMut", variant_name), variant_name.span());
|
||||||
let variant_accessor = get_accessor(&serde_rename_all, &variant.attrs, variant_name);
|
let variant_accessor = get_accessor(&serde_rename_all, &variant.attrs, variant_name);
|
||||||
tag_variants.extend(quote_spanned! { variant_name.span() =>
|
tag_variants.extend(quote_spanned! { variant_name.span() =>
|
||||||
if value.as_object().map(|o| o.contains_key(#variant_accessor)).unwrap_or(false) {
|
if value.as_object().map(|o| o.contains_key(#variant_accessor)).unwrap_or(false) {
|
||||||
Model::#variant_name(#variant_model(value))
|
Model::#variant_name(#variant_model(value[#variant_accessor].clone()))
|
||||||
|
} else
|
||||||
|
});
|
||||||
|
tag_variants_mut.extend(quote_spanned! { variant_name.span() =>
|
||||||
|
if value.as_object().map(|o| o.contains_key(#variant_accessor)).unwrap_or(false) {
|
||||||
|
ModelMut::#variant_name(#variant_model_mut(&mut value[#variant_accessor]))
|
||||||
} else
|
} else
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
quote! {
|
(
|
||||||
#tag_variants {
|
quote! {
|
||||||
Model::Error(value),
|
#tag_variants {
|
||||||
}
|
Model::Error(value),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
quote! {
|
||||||
|
#tag_variants_mut {
|
||||||
|
ModelMut::Error(value),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
};
|
};
|
||||||
for variant in &ast.variants {
|
for variant in &ast.variants {
|
||||||
let name = &variant.ident;
|
let name = &variant.ident;
|
||||||
let model_name = Ident::new(&format!("{}Model", variant.ident), variant.ident.span());
|
let model_name = Ident::new(&format!("{}Model", variant.ident), variant.ident.span());
|
||||||
|
let model_name_mut =
|
||||||
|
Ident::new(&format!("{}ModelMut", variant.ident), variant.ident.span());
|
||||||
let serde_rename_all = variant
|
let serde_rename_all = variant
|
||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
@@ -434,7 +542,10 @@ fn build_model_enum(base: &DeriveInput, ast: &DataEnum, module_name: Option<Iden
|
|||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
model_variants.extend(quote_spanned! { name.span() =>
|
model_variants.extend(quote_spanned! { name.span() =>
|
||||||
#name(#model_name<'a>),
|
#name(#model_name),
|
||||||
|
});
|
||||||
|
mut_model_variants.extend(quote_spanned! { name.span() =>
|
||||||
|
#name(#model_name_mut<'a>),
|
||||||
});
|
});
|
||||||
let children: Vec<_> = ChildInfo::from_fields(&serde_rename_all, &variant.fields)
|
let children: Vec<_> = ChildInfo::from_fields(&serde_rename_all, &variant.fields)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -445,82 +556,154 @@ fn build_model_enum(base: &DeriveInput, ast: &DataEnum, module_name: Option<Iden
|
|||||||
..c
|
..c
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let impl_fns = impl_fns(&children);
|
let Fns {
|
||||||
|
impl_fns,
|
||||||
|
impl_mut_fns,
|
||||||
|
} = impl_fns(&children);
|
||||||
decl_model_variants.extend(quote_spanned! { name.span() =>
|
decl_model_variants.extend(quote_spanned! { name.span() =>
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct #model_name<'a>(&'a mut patch_db::Value);
|
pub struct #model_name(patch_db::Value);
|
||||||
impl<'a> ::core::ops::Deref for #model_name<'a> {
|
impl ::core::ops::Deref for #model_name {
|
||||||
|
type Target = patch_db::Value;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ::core::ops::DerefMut for #model_name {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl #model_name {
|
||||||
|
#impl_fns
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct #model_name_mut<'a>(&'a mut patch_db::Value);
|
||||||
|
impl<'a> ::core::ops::Deref for #model_name_mut<'a> {
|
||||||
type Target = patch_db::Value;
|
type Target = patch_db::Value;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&*self.0
|
&*self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> ::core::ops::DerefMut for #model_name<'a> {
|
impl<'a> ::core::ops::DerefMut for #model_name_mut<'a> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> #model_name<'a> {
|
impl<'a> #model_name_mut<'a> {
|
||||||
#impl_fns
|
#impl_mut_fns
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
into_inner.extend(quote_spanned! { name.span() =>
|
into_inner.extend(quote_spanned! { name.span() =>
|
||||||
Model::#name(a) => a.0,
|
Model::#name(a) => a.0,
|
||||||
});
|
});
|
||||||
deref.extend(quote_spanned! { name.span() =>
|
deref.extend(quote_spanned! { name.span() =>
|
||||||
Model::#name(a) => &*a,
|
Model::#name(a) => &a.0,
|
||||||
});
|
});
|
||||||
deref_mut.extend(quote_spanned! { name.span() =>
|
deref_mut.extend(quote_spanned! { name.span() =>
|
||||||
Model::#name(a) => &mut *a,
|
Model::#name(a) => &mut a.0,
|
||||||
|
});
|
||||||
|
mut_into_inner.extend(quote_spanned! { name.span() =>
|
||||||
|
ModelMut::#name(a) => a.0,
|
||||||
|
});
|
||||||
|
mut_deref.extend(quote_spanned! { name.span() =>
|
||||||
|
ModelMut::#name(a) => &*a,
|
||||||
|
});
|
||||||
|
mut_deref_mut.extend(quote_spanned! { name.span() =>
|
||||||
|
ModelMut::#name(a) => &mut *a,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let name = &base.ident;
|
let name = &base.ident;
|
||||||
let vis = &base.vis;
|
let vis = &base.vis;
|
||||||
let impl_fns = impl_fns(&children);
|
let Fns {
|
||||||
|
impl_fns,
|
||||||
|
impl_mut_fns,
|
||||||
|
} = impl_fns(&children);
|
||||||
quote! {
|
quote! {
|
||||||
impl<'a> patch_db::HasModel<'a> for #name {
|
impl patch_db::HasModel for #name {
|
||||||
type Model = #module_name::Model<'a>;
|
type Model = #module_name::Model;
|
||||||
}
|
}
|
||||||
#vis mod #module_name {
|
#vis mod #module_name {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Model<'a> {
|
pub enum Model {
|
||||||
#model_variants
|
#model_variants
|
||||||
Error(&'a mut patch_db::Value),
|
Error(patch_db::Value),
|
||||||
}
|
}
|
||||||
impl<'a> patch_db::Model<'a> for Model<'a> {
|
impl patch_db::Model for Model {
|
||||||
type T = #name;
|
type T = #name;
|
||||||
fn new(value: &'a mut patch_db::Value) -> Self {
|
type Mut<'a> = ModelMut<'a>;
|
||||||
|
fn new(value: patch_db::Value) -> Self {
|
||||||
#impl_new
|
#impl_new
|
||||||
}
|
}
|
||||||
fn into_inner(self) -> &'a mut patch_db::Value {
|
fn into_inner(self) -> patch_db::Value {
|
||||||
match self {
|
match self {
|
||||||
#into_inner
|
#into_inner
|
||||||
Model::Error(a) => a,
|
Model::Error(a) => a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> ::core::ops::Deref for Model<'a> {
|
impl ::core::ops::Deref for Model {
|
||||||
type Target = patch_db::Value;
|
type Target = patch_db::Value;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match self {
|
match self {
|
||||||
#deref
|
#deref
|
||||||
Model::Error(a) => &*a,
|
Model::Error(a) => &a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> ::core::ops::DerefMut for Model<'a> {
|
impl ::core::ops::DerefMut for Model {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
match self {
|
match self {
|
||||||
#deref_mut
|
#deref_mut
|
||||||
Model::Error(a) => a,
|
Model::Error(a) => &mut a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Model<'a> {
|
impl Model {
|
||||||
#impl_fns
|
#impl_fns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ModelMut<'a> {
|
||||||
|
#mut_model_variants
|
||||||
|
Error(&'a mut patch_db::Value),
|
||||||
|
}
|
||||||
|
impl<'a> patch_db::ModelMut<'a> for ModelMut<'a> {
|
||||||
|
type T = #name;
|
||||||
|
fn new(value: &'a mut patch_db::Value) -> Self {
|
||||||
|
#impl_new_mut
|
||||||
|
}
|
||||||
|
fn into_inner(self) -> &'a mut patch_db::Value {
|
||||||
|
match self {
|
||||||
|
#mut_into_inner
|
||||||
|
ModelMut::Error(a) => a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> ::core::ops::Deref for ModelMut<'a> {
|
||||||
|
type Target = patch_db::Value;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
#mut_deref
|
||||||
|
ModelMut::Error(a) => &*a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> ::core::ops::DerefMut for ModelMut<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
match self {
|
||||||
|
#mut_deref_mut
|
||||||
|
ModelMut::Error(a) => a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> ModelMut<'a> {
|
||||||
|
#impl_mut_fns
|
||||||
|
}
|
||||||
|
|
||||||
#decl_model_variants
|
#decl_model_variants
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ mod test;
|
|||||||
|
|
||||||
pub use imbl_value as value;
|
pub use imbl_value as value;
|
||||||
pub use imbl_value::Value;
|
pub use imbl_value::Value;
|
||||||
pub use model::{GenericModel, HasModel, Map, MapModel, Model, OptionModel};
|
pub use model::{
|
||||||
|
GenericModel, GenericModelMut, HasModel, Model, ModelMut, OptionModel, OptionModelMut,
|
||||||
|
};
|
||||||
pub use patch::{DiffPatch, Dump, Revision};
|
pub use patch::{DiffPatch, Dump, Revision};
|
||||||
pub use patch_db_macro::HasModel;
|
pub use patch_db_macro::HasModel;
|
||||||
pub use store::{PatchDb, Store};
|
pub use store::{PatchDb, Store};
|
||||||
|
|||||||
@@ -1,16 +1,34 @@
|
|||||||
use std::collections::{BTreeMap, BTreeSet};
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use imbl_value::Value;
|
use imbl_value::Value;
|
||||||
use serde::de::{DeserializeOwned, Error};
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
pub trait HasModel<'a> {
|
pub trait HasModel {
|
||||||
type Model: Model<'a>;
|
type Model: Model;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Model<'a>: Deref<Target = Value> + DerefMut {
|
pub trait Model: Deref<Target = Value> + DerefMut {
|
||||||
|
type T: DeserializeOwned + Serialize;
|
||||||
|
type Mut<'a>: ModelMut<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
fn new(value: Value) -> Self;
|
||||||
|
fn into_inner(self) -> Value;
|
||||||
|
fn as_mut<'a>(&'a mut self) -> Self::Mut<'a> {
|
||||||
|
Self::Mut::new(&mut *self)
|
||||||
|
}
|
||||||
|
fn set(&mut self, value: &Self::T) -> Result<(), imbl_value::Error> {
|
||||||
|
*self.deref_mut() = imbl_value::to_value(value)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn get(&self) -> Result<Self::T, imbl_value::Error> {
|
||||||
|
imbl_value::from_value(self.deref().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ModelMut<'a>: Deref<Target = Value> + DerefMut {
|
||||||
type T: DeserializeOwned + Serialize;
|
type T: DeserializeOwned + Serialize;
|
||||||
fn new(value: &'a mut Value) -> Self;
|
fn new(value: &'a mut Value) -> Self;
|
||||||
fn into_inner(self) -> &'a mut Value;
|
fn into_inner(self) -> &'a mut Value;
|
||||||
@@ -23,25 +41,54 @@ pub trait Model<'a>: Deref<Target = Value> + DerefMut {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GenericModel<'a, T> {
|
pub struct GenericModel<T> {
|
||||||
|
value: Value,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
impl<T> Deref for GenericModel<T> {
|
||||||
|
type Target = Value;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> DerefMut for GenericModel<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: DeserializeOwned + Serialize> Model for GenericModel<T> {
|
||||||
|
type T = T;
|
||||||
|
type Mut<'a> = GenericModelMut<'a, T> where T: 'a;
|
||||||
|
fn new(value: Value) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn into_inner(self) -> Value {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GenericModelMut<'a, T> {
|
||||||
value: &'a mut Value,
|
value: &'a mut Value,
|
||||||
phantom: PhantomData<T>,
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
impl<'a, T> Deref for GenericModel<'a, T> {
|
impl<'a, T> Deref for GenericModelMut<'a, T> {
|
||||||
type Target = Value;
|
type Target = Value;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&*self.value
|
&*self.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T> DerefMut for GenericModel<'a, T> {
|
impl<'a, T> DerefMut for GenericModelMut<'a, T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T: DeserializeOwned + Serialize> Model<'a> for GenericModel<'a, T> {
|
impl<'a, T: DeserializeOwned + Serialize> ModelMut<'a> for GenericModelMut<'a, T> {
|
||||||
type T = T;
|
type T = T;
|
||||||
fn new(value: &'a mut Value) -> Self {
|
fn new(value: &'a mut Value) -> Self {
|
||||||
GenericModel {
|
Self {
|
||||||
value,
|
value,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@@ -51,167 +98,78 @@ impl<'a, T: DeserializeOwned + Serialize> Model<'a> for GenericModel<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Map<'a>: DeserializeOwned + Serialize {
|
pub struct OptionModel<T: Model> {
|
||||||
type Key: AsRef<str>;
|
value: Value,
|
||||||
type Value: HasModel<'a>;
|
|
||||||
fn get(&self, key: &Self::Key) -> Option<&Self::Value>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MapModel<'a, T: Map<'a>> {
|
|
||||||
value: &'a mut Value,
|
|
||||||
phantom: PhantomData<T>,
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
impl<'a, T: Map<'a>> Deref for MapModel<'a, T> {
|
|
||||||
type Target = Value;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&*self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, T: Map<'a>> DerefMut for MapModel<'a, T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, T: Map<'a>> Model<'a> for MapModel<'a, T> {
|
|
||||||
type T = T;
|
|
||||||
fn new(value: &'a mut Value) -> Self {
|
|
||||||
MapModel {
|
|
||||||
value,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn into_inner(self) -> &'a mut Value {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, T: Map<'a>> MapModel<'a, T> {
|
|
||||||
pub fn idx(self, key: &T::Key) -> Option<<T::Value as HasModel<'a>>::Model> {
|
|
||||||
match self.value {
|
|
||||||
Value::Object(o) => o
|
|
||||||
.get_mut(key.as_ref())
|
|
||||||
.map(<T::Value as HasModel<'a>>::Model::new),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, T: Map<'a>> MapModel<'a, T>
|
|
||||||
where
|
|
||||||
T::Value: Serialize,
|
|
||||||
{
|
|
||||||
pub fn put(&'a mut self, key: &T::Key, value: &T::Value) -> Result<(), imbl_value::Error> {
|
|
||||||
if let Some(o) = self.value.as_object_mut() {
|
|
||||||
o.insert(key.as_ref().to_owned().into(), imbl_value::to_value(value)?);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(imbl_value::Error::custom("expected object"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, T: Map<'a>> MapModel<'a, T>
|
|
||||||
where
|
|
||||||
T::Key: DeserializeOwned + Ord + Eq,
|
|
||||||
{
|
|
||||||
pub fn keys(&self) -> Result<BTreeSet<T::Key>, imbl_value::Error> {
|
|
||||||
self.as_object()
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|o| o.keys())
|
|
||||||
.cloned()
|
|
||||||
.map(|k| imbl_value::from_value(Value::String(k)))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
pub fn entries(
|
|
||||||
&'a mut self,
|
|
||||||
) -> Result<BTreeMap<T::Key, <T::Value as HasModel>::Model>, imbl_value::Error> {
|
|
||||||
self.as_object_mut()
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|o| o.iter_mut())
|
|
||||||
.map(|(k, v)| {
|
|
||||||
Ok((
|
|
||||||
imbl_value::from_value(Value::String(k.clone()))?,
|
|
||||||
<T::Value as HasModel>::Model::new(v),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NullRef<'a, T> {
|
impl<T: Model> OptionModel<T> {
|
||||||
value: Option<&'a mut Value>,
|
|
||||||
phantom: PhantomData<T>,
|
|
||||||
}
|
|
||||||
impl<'a, T: Model<'a>> NullRef<'a, T> {
|
|
||||||
pub fn set(self, value: &T::T) -> Result<(), imbl_value::Error> {
|
|
||||||
*self.value.unwrap() = imbl_value::to_value(value)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum OptionModel<'a, T: Model<'a>> {
|
|
||||||
Some(T),
|
|
||||||
None(NullRef<'a, T>),
|
|
||||||
}
|
|
||||||
impl<'a, T: Model<'a> + 'a> OptionModel<'a, T> {
|
|
||||||
pub fn check(self) -> Option<T> {
|
pub fn check(self) -> Option<T> {
|
||||||
match self {
|
if self.is_null() {
|
||||||
OptionModel::Some(a) => Some(a),
|
None
|
||||||
_ => None,
|
} else {
|
||||||
|
Some(T::new(self.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T: Model<'a>> Deref for OptionModel<'a, T> {
|
impl<T: Model> Deref for OptionModel<T> {
|
||||||
type Target = Value;
|
type Target = Value;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match self {
|
&self.value
|
||||||
OptionModel::None(a) => &*a.value.as_ref().unwrap(),
|
|
||||||
OptionModel::Some(a) => &**a,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T: Model<'a>> DerefMut for OptionModel<'a, T> {
|
impl<T: Model> DerefMut for OptionModel<T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
match self {
|
&mut self.value
|
||||||
OptionModel::None(a) => &mut *a.value.as_mut().unwrap(),
|
}
|
||||||
OptionModel::Some(a) => &mut *a,
|
}
|
||||||
|
impl<T: Model> Model for OptionModel<T> {
|
||||||
|
type T = Option<T::T>;
|
||||||
|
type Mut<'a> = OptionModelMut<'a, T::Mut<'a>> where T: 'a;
|
||||||
|
fn new(value: Value) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn into_inner(self) -> Value {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OptionModelMut<'a, T: ModelMut<'a>> {
|
||||||
|
value: &'a mut Value,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
impl<'a, T: ModelMut<'a>> OptionModelMut<'a, T> {
|
||||||
|
pub fn check(self) -> Option<T> {
|
||||||
|
if self.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(T::new(self.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T: Model<'a>> Model<'a> for OptionModel<'a, T> {
|
impl<'a, T: ModelMut<'a>> Deref for OptionModelMut<'a, T> {
|
||||||
|
type Target = Value;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&*self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T: ModelMut<'a>> DerefMut for OptionModelMut<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T: ModelMut<'a>> ModelMut<'a> for OptionModelMut<'a, T> {
|
||||||
type T = Option<T::T>;
|
type T = Option<T::T>;
|
||||||
fn new(value: &'a mut Value) -> Self {
|
fn new(value: &'a mut Value) -> Self {
|
||||||
if value.is_null() {
|
Self {
|
||||||
OptionModel::None(NullRef {
|
value,
|
||||||
value: Some(value),
|
phantom: PhantomData,
|
||||||
phantom: PhantomData,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
OptionModel::Some(T::new(value))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn into_inner(self) -> &'a mut Value {
|
fn into_inner(self) -> &'a mut Value {
|
||||||
match self {
|
self.value
|
||||||
OptionModel::None(a) => a.value.unwrap(),
|
|
||||||
OptionModel::Some(a) => a.into_inner(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn set(&mut self, value: &Self::T) -> Result<(), imbl_value::Error> {
|
|
||||||
let value = imbl_value::to_value(value)?;
|
|
||||||
let old = std::mem::replace(
|
|
||||||
self,
|
|
||||||
OptionModel::None(NullRef {
|
|
||||||
value: None,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.into_inner();
|
|
||||||
*old = value;
|
|
||||||
*self = if old.is_null() {
|
|
||||||
OptionModel::None(NullRef {
|
|
||||||
value: Some(old),
|
|
||||||
phantom: PhantomData,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
OptionModel::Some(T::new(old))
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,27 +352,22 @@ impl PatchDb {
|
|||||||
let rev = store.apply(patch).await?;
|
let rev = store.apply(patch).await?;
|
||||||
Ok(rev)
|
Ok(rev)
|
||||||
}
|
}
|
||||||
pub async fn apply_func<F, T, E>(&self, f: F) -> Result<T, E>
|
pub async fn apply_function<F, T, E>(&self, f: F) -> Result<(Value, T), E>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Value) -> Result<T, E> + UnwindSafe,
|
F: FnOnce(Value) -> Result<(Value, T), E> + UnwindSafe,
|
||||||
E: From<Error>,
|
E: From<Error>,
|
||||||
{
|
{
|
||||||
let mut store = self.store.write().await;
|
let mut store = self.store.write().await;
|
||||||
let mut old = store.persistent.clone();
|
let old = store.persistent.clone();
|
||||||
let (new, res) = std::panic::catch_unwind(move || {
|
let (new, res) = std::panic::catch_unwind(move || f(old)).map_err(|e| {
|
||||||
let res = f(&mut old);
|
|
||||||
(old, res)
|
|
||||||
})
|
|
||||||
.map_err(|e| {
|
|
||||||
Error::Panick(
|
Error::Panick(
|
||||||
e.downcast()
|
e.downcast()
|
||||||
.map(|a| *a)
|
.map(|a| *a)
|
||||||
.unwrap_or_else(|_| "UNKNOWN".to_owned()),
|
.unwrap_or_else(|_| "UNKNOWN".to_owned()),
|
||||||
)
|
)
|
||||||
})?;
|
})??;
|
||||||
let res = res?;
|
|
||||||
let diff = diff(&store.persistent, &new);
|
let diff = diff(&store.persistent, &new);
|
||||||
store.apply(diff).await?;
|
store.apply(diff).await?;
|
||||||
Ok(res)
|
Ok((new, res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user