Skip to content

Commit

Permalink
Feat recursion (#46)
Browse files Browse the repository at this point in the history
feat: recursion Support recursion in the serialization schema graph
  • Loading branch information
avl authored Apr 30, 2024
1 parent a8d9580 commit 5ccb8de
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 211 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion savefile-abi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.17.-beta.13](https://github.com/avl/savefile/compare/savefile-abi-v0.17.0-beta.12...savefile-abi-v0.17.0-beta.13) - 2024-04-27
## [0.17.0-beta.14](https://github.com/avl/savefile/compare/savefile-abi-v0.17.0-beta.13...savefile-abi-v0.17.0-beta.14) - 2024-04-30

### Other
- updated the following local packages: savefile, savefile-derive

## [0.17.0-beta.13](https://github.com/avl/savefile/compare/savefile-abi-v0.17.0-beta.12...savefile-abi-v0.17.0-beta.13) - 2024-04-27

### Other
- updated the following local packages: savefile
Expand Down
6 changes: 3 additions & 3 deletions savefile-abi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "savefile-abi"
version = "0.17.0-beta.13"
version = "0.17.0-beta.14"
edition = "2021"
authors = ["Anders Musikka <[email protected]>"]
documentation = "https://docs.rs/savefile-abi/"
Expand All @@ -16,7 +16,7 @@ keywords = ["dylib", "dlopen", "ffi"]
license = "MIT/Apache-2.0"

[dependencies]
savefile = { path="../savefile", version = "=0.17.0-beta.13" }
savefile-derive = { path="../savefile-derive", version = "=0.17.0-beta.13" }
savefile = { path="../savefile", version = "=0.17.0-beta.14" }
savefile-derive = { path="../savefile-derive", version = "=0.17.0-beta.14" }
byteorder = "1.4"
libloading = "0.8"
33 changes: 17 additions & 16 deletions savefile-abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,8 @@ pub struct TraitObject {
vtable: *const (),
}

unsafe impl Sync for TraitObject {

}
unsafe impl Send for TraitObject {

}
unsafe impl Sync for TraitObject {}
unsafe impl Send for TraitObject {}

impl TraitObject {
/// Returns a TraitObject with two null ptrs. This value must never be used,
Expand Down Expand Up @@ -617,12 +613,8 @@ pub struct AbiConnection<T: ?Sized> {
#[doc(hidden)]
pub phantom: PhantomData<*const T>,
}
unsafe impl<T:?Sized> Sync for AbiConnection<T>{

}
unsafe impl<T:?Sized> Send for AbiConnection<T>{

}
unsafe impl<T: ?Sized> Sync for AbiConnection<T> {}
unsafe impl<T: ?Sized> Send for AbiConnection<T> {}

/// A trait object together with its entry point
#[repr(C)]
Expand Down Expand Up @@ -1324,15 +1316,24 @@ impl<T: AbiExportable + ?Sized> AbiConnection<T> {
/// of the code being called into. It will not change during the lifetime of an
/// AbiConnector, but it may change if the target library is recompiled.
pub fn get_arg_passable_by_ref(&self, method: &str, arg: usize) -> bool {
if let Some(found) = self.template.methods.iter().find(|var|var.method_name == method) {
if let Some(found) = self.template.methods.iter().find(|var| var.method_name == method) {
let abi_method: &AbiConnectionMethod = found;
if arg >= abi_method.caller_info.arguments.len() {
panic!("Method '{}' has only {} arguments, so there is no argument #{}", method, abi_method.caller_info.arguments.len(), arg);
panic!(
"Method '{}' has only {} arguments, so there is no argument #{}",
method,
abi_method.caller_info.arguments.len(),
arg
);
}
(abi_method.compatibility_mask & (1 << (arg as u64))) != 0
} else {
let arg_names : Vec<_> = self.template.methods.iter().map(|x|x.method_name.as_str()).collect();
panic!("Trait has no method with name '{}'. Available methods: {}", method, arg_names.join(", "));
let arg_names: Vec<_> = self.template.methods.iter().map(|x| x.method_name.as_str()).collect();
panic!(
"Trait has no method with name '{}'. Available methods: {}",
method,
arg_names.join(", ")
);
}
}

Expand Down
5 changes: 5 additions & 0 deletions savefile-derive/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.17.0-beta.14](https://github.com/avl/savefile/compare/savefile-derive-v0.17.0-beta.13...savefile-derive-v0.17.0-beta.14) - 2024-04-30

### Fixed
- Bad cycles detection

## [0.17.0-beta.12](https://github.com/avl/savefile/compare/savefile-derive-v0.17.0-beta.11...savefile-derive-v0.17.0-beta.12) - 2024-04-27

### Other
Expand Down
2 changes: 1 addition & 1 deletion savefile-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "savefile-derive"
version = "0.17.0-beta.13"
version = "0.17.0-beta.14"
authors = ["Anders Musikka <[email protected]>"]

description = "Custom derive macros for savefile crate - simple, convenient, fast, versioned, binary serialization/deserialization library."
Expand Down
64 changes: 49 additions & 15 deletions savefile-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ use syn::__private::bool;
use syn::spanned::Spanned;
use syn::token::Paren;
use syn::Type::Tuple;
use syn::{DeriveInput, FnArg, GenericParam, Generics, Ident, ImplGenerics, Index, ItemTrait, Pat, ReturnType, TraitItem, Type, TypeGenerics, TypeParamBound, TypeTuple};
use syn::{
DeriveInput, FnArg, GenericParam, Generics, Ident, ImplGenerics, Index, ItemTrait, Pat, ReturnType, TraitItem,
Type, TypeGenerics, TypeParamBound, TypeTuple,
};
fn implement_fields_serialize(
field_infos: Vec<FieldInfo>,
implicit_self: bool,
Expand Down Expand Up @@ -253,7 +256,7 @@ pub fn savefile_abi_exportable(
let uses = quote_spanned! { defspan =>
extern crate savefile;
extern crate savefile_abi;
use savefile::prelude::{ReprC, Schema, SchemaPrimitive, WithSchema, WithSchemaContext, Serializer, Serialize, Deserializer, Deserialize, SavefileError, deserialize_slice_as_vec, ReadBytesExt,LittleEndian,AbiMethodArgument, AbiMethod, AbiMethodInfo,AbiTraitDefinition};
use savefile::prelude::{ReprC, Schema, SchemaPrimitive, WithSchema, WithSchemaContext, get_schema, Serializer, Serialize, Deserializer, Deserialize, SavefileError, deserialize_slice_as_vec, ReadBytesExt,LittleEndian,AbiMethodArgument, AbiMethod, AbiMethodInfo,AbiTraitDefinition};
use savefile_abi::{parse_return_value_impl,abi_result_receiver,abi_boxed_trait_receiver, FlexBuffer, AbiExportable, TraitObject, PackagedTraitObject, Owning, AbiErrorMsg, RawAbiCallResult, AbiConnection, AbiConnectionMethod, AbiProtocol, abi_entry_light};
use std::collections::HashMap;
use std::mem::MaybeUninit;
Expand All @@ -266,7 +269,10 @@ pub fn savefile_abi_exportable(
let mut extra_definitions = HashMap::new();

if parsed.generics.params.is_empty() == false {
abort!(parsed.generics.params.span(), "Savefile does not support generic traits.");
abort!(
parsed.generics.params.span(),
"Savefile does not support generic traits."
);
}
for supertrait in parsed.supertraits.iter() {
match supertrait {
Expand All @@ -293,7 +299,10 @@ pub fn savefile_abi_exportable(
}

if parsed.generics.where_clause.is_some() {
abort!(parsed.generics.where_clause.span(), "Savefile does not support where-clauses for traits");
abort!(
parsed.generics.where_clause.span(),
"Savefile does not support where-clauses for traits"
);
}

for (method_number, item) in parsed.items.iter().enumerate() {
Expand All @@ -312,7 +321,10 @@ pub fn savefile_abi_exportable(
}
TraitItem::Method(method) => {
if method.sig.generics.where_clause.is_some() {
abort!(method.sig.generics.where_clause.span(), "Savefile does not support where-clauses for methods");
abort!(
method.sig.generics.where_clause.span(),
"Savefile does not support where-clauses for methods"
);
}
let method_name = method.sig.ident.clone();
//let method_name_str = method.sig.ident.to_string();
Expand Down Expand Up @@ -392,26 +404,42 @@ pub fn savefile_abi_exportable(
}
}
if method.sig.asyncness.is_some() {
abort!(method.sig.asyncness.span(), "savefile-abi does not support async methods.")
abort!(
method.sig.asyncness.span(),
"savefile-abi does not support async methods."
)
}
if method.sig.variadic.is_some() {
abort!(method.sig.variadic.span(), "savefile-abi does not support variadic methods.")
abort!(
method.sig.variadic.span(),
"savefile-abi does not support variadic methods."
)
}
if method.sig.unsafety.is_some() {
abort!(method.sig.unsafety.span(), "savefile-abi does not presently support unsafe methods.")
abort!(
method.sig.unsafety.span(),
"savefile-abi does not presently support unsafe methods."
)
}
if method.sig.abi.is_some() {
abort!(method.sig.abi.span(), "savefile-abi does not need (or support) 'extern \"C\"' or similar ABI-constructs. Just remove this keyword.")
}
if method.sig.generics.params.is_empty() == false {
for item in method.sig.generics.params.iter() {
match item {
GenericParam::Type(typ) => abort!(typ.span(), "savefile-abi does not support generic methods."),
GenericParam::Const(typ) => abort!(typ.span(), "savefile-abi does not support const-generic methods."),
GenericParam::Type(typ) => {
abort!(typ.span(), "savefile-abi does not support generic methods.")
}
GenericParam::Const(typ) => {
abort!(typ.span(), "savefile-abi does not support const-generic methods.")
}
_ => {}
}
}
abort!(method.sig.generics.params.span(), "savefile-abi does not support methods with lifetimes.");
abort!(
method.sig.generics.params.span(),
"savefile-abi does not support methods with lifetimes."
);
}

let method_defs = crate::savefile_abi::generate_method_definitions(
Expand Down Expand Up @@ -446,9 +474,17 @@ pub fn savefile_abi_exportable(
);
}
TraitItem::Verbatim(v) => {
abort!(v.span(), "Unsupported item in trait definition: {}", v.to_token_stream());
abort!(
v.span(),
"Unsupported item in trait definition: {}",
v.to_token_stream()
);
}
x => abort!(x.span(), "Unsupported item in trait definition: {}", x.to_token_stream()),
x => abort!(
x.span(),
"Unsupported item in trait definition: {}",
x.to_token_stream()
),
}
}

Expand Down Expand Up @@ -544,8 +580,6 @@ pub fn savefile_abi_export(item: proc_macro::TokenStream) -> proc_macro::TokenSt
let trait_type = Ident::new(symbols[1], Span::call_site());
let abi_entry = Ident::new(("abi_entry_".to_string() + symbols[1]).as_str(), Span::call_site());



let expanded = quote! {
#[allow(clippy::double_comparisons)]
const _:() = {
Expand Down
Loading

0 comments on commit 5ccb8de

Please sign in to comment.