Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to serialize and Deserialize closure? #24

Open
TrionProg opened this issue Jan 11, 2020 · 9 comments
Open

How to serialize and Deserialize closure? #24

TrionProg opened this issue Jan 11, 2020 · 9 comments

Comments

@TrionProg
Copy link

Hello, I am trying to do it.

You wrote:

you either need to specify the precise type you're deserializing without naming it (which is possible but not particularly practical)

How to do it(to deserialize)?

I use serde_traitobject and write this code

use serde_traitobject as st;

let one:usize = 1;
let two:usize = 2;
let plus_one = Fn!(|x: usize| x + one + two);

let s: st::Box<dyn serde_traitobject::Fn(usize) -> usize> = st::Box::new(plus_one);

let serialized = serde_json::to_string(&s).unwrap();
println!("{}",serialized);

let deserialized: st::Box<dyn serde_traitobject::Fn(usize) -> usize> = serde_json::from_str(serialized.as_str()).unwrap();

And I have error:
the trait bound `&usize: main::_IMPL_DESERIALIZE_FOR_MyStruct::_serde::Deserialize<'_>` is not satisfied

What should I do?

Can I create struct with two or more closures and serialize and deserialize it? Without Box<dyn ... Fn> just Box?

@alecmocatta
Copy link
Owner

alecmocatta commented Jan 15, 2020

Hi @TrionProg, thanks for filing an issue!

I think the problem is that the closure here needs to be a move closure to take ownership of the captured variables (one and two), rather than take references to them. This is because it's not possible to deserialize to a reference (your error message shows it's trying to deserialize to a &usize, which isn't possible).

This should work:

let plus_one = Fn!(move |x: usize| x + one + two);

Can I create struct with two or more closures and serialize and deserialize it? Without Box<dyn ... Fn> just Box?

Boxing the closure's trait object, i.e. Box<dyn ... Fn>, is necessary in most use cases. A struct containing multiple closures could look like:

struct MultipleClosures {
    a: Box<dyn st::Fn(usize) -> usize>,
    b: Box<dyn st::Fn(usize) -> usize>,
}

@TrionProg
Copy link
Author

TrionProg commented Jan 22, 2020

Hello.
Hm. Yes, I've forgotten move. And now it works.

Unfortunately I need use 2 boxes in the struct, + 1 box for this struct. Later, I hope, I will try to optimize it to MultipleClosures<F1,F2>, this should be simmilar to error_impl in failure library:

Box<Inner<Fail>> 
struct Inner<E:Fail> {
  backtrace
  error:E
}

Thank you for your fantastic library!

@TrionProg
Copy link
Author

TrionProg commented Jan 23, 2020

Hello. Ohh, not all is right. I can not show the code -- it has a lot of garbage and I can not understand anything that happens -- All works, but then I implement Trait, I have a lot of problems like Self: traitobject::Sealed is not satisfied.

Can you give me an example how to:
Create trait(MyTrait), that wants Self(MultipleClosures) be serializable (by your library). And Just create MultipleClosures, insert it in Boxand it will serialize and deserialize it. MultipleClosures has one generic as parameter, It should not be stored in this struct, for example, closure a returns it.

@TrionProg
Copy link
Author

TrionProg commented Jan 24, 2020

Okey. I am making experiment. Minimal example of same error.

#![feature(unboxed_closures)]

extern crate serde;
extern crate serde_traitobject;

#[macro_use]
extern crate serde_closure;

#[macro_use]
extern crate serde_derive;

use serde_traitobject::FnOnce as FnOnceTO;
use serde_traitobject::Box as BoxTO;

use serde_traitobject::{
    Serialize as SerializeTO,
    Deserialize as DeserializeTO
};

use serde_derive::{Serialize, Deserialize};

use std::marker::PhantomData;

pub trait BlockTrait: SerializeTO + DeserializeTO{
    fn exec(&mut self) -> bool;
}

#[derive(Serialize, Deserialize)]
struct TwoClosures<T> where
    T:'static
{
    inner: Option<TwoClosuresInner<T>>
}

#[derive(Serialize, Deserialize)]
struct TwoClosuresInner<T> where
    T:'static
{
    #[serde(with = "serde_traitobject")]
    a: Box<FnOnceTO() -> T>,
    #[serde(with = "serde_traitobject")]
    b: Box<FnOnceTO(T) -> bool>,
    _phantom_data:PhantomData<T>
}

impl<T> TwoClosures<T> where
{
    fn new<A, B>(a:A, b:B) -> Self where
        A: FnOnceTO() -> T + 'static,
        B: FnOnceTO(T) -> bool + 'static
    {
        let inner = TwoClosuresInner {
            a: Box::new(a),
            b: Box::new(b),
            _phantom_data: PhantomData
        };

        TwoClosures {
            inner: Some(inner)
        }
    }
}

impl<T> BlockTrait for TwoClosures<T> {
    fn exec(&mut self) -> bool {
        let inner = self.inner.extract();
        let t = (inner.a)();
        (inner.b)(t)
    }
}

fn main() {
    let tc = TwoClosures::new(
        FnOnce!(|| 8usize),
        FnOnce!(move|v|v==8),
    );

    let tc_box:BoxTO<dyn BlockTrait> = BoxTO::new(tc);

    let serialized = serde_json::to_string(&tc_box).unwrap();
    println!("{}",serialized);
}

And errors. It wants T to be serializable, but it is 'static.

error[E0277]: the trait bound `TwoClosures<T>: serde_traitobject::serialize::Sealed` is not satisfied
  --> src\main.rs:67:9
   |
67 | impl<T> BlockTrait for TwoClosures<T> {
   |         ^^^^^^^^^^ the trait `serde_traitobject::serialize::Sealed` is not implemented for `TwoClosures<T>`

error[E0277]: the trait bound `T: serde::Serialize` is not satisfied
  --> src\main.rs:67:9
   |
67 | impl<T> BlockTrait for TwoClosures<T> {
   |      -  ^^^^^^^^^^ the trait `serde::Serialize` is not implemented for `T`
   |      |
   |      help: consider restricting this bound: `T: serde::Serialize`
   |
   = note: required because of the requirements on the impl of `serde::Serialize` for `TwoClosures<T>`
   = note: required because of the requirements on the impl of `serde_traitobject::Serialize` for `TwoClosures<T>`

error[E0277]: the trait bound `T: serde::Deserialize<'_>` is not satisfied
  --> src\main.rs:67:9
   |
67 | impl<T> BlockTrait for TwoClosures<T> {
   |      -  ^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `T`
   |      |
   |      help: consider restricting this bound: `T: serde::Deserialize<'_>`
   |
   = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `TwoClosures<T>`
   = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `TwoClosures<T>`
   = note: required because of the requirements on the impl of `serde_traitobject::Deserialize` for `TwoClosures<T>`

UPD.

I want to do not haul this 'de, but I try:

pub trait BlockTrait<'de>: Serialize + Deserialize<'de>{
    fn exec(&mut self) -> bool;
}

impl<'de, T> BlockTrait<'de> for TwoClosures<T> {
    fn exec(&mut self) -> bool {
        let inner = self.inner.extract();
        let t = (inner.a)();
        (inner.b)(t)
    }
}

And it wants T:Serialize, T:Deserialize =(

@TrionProg
Copy link
Author

TrionProg commented Jan 24, 2020

And second question: how to serialize struct TwoClosures by may hands without derive?

@alecmocatta
Copy link
Owner

alecmocatta commented Jan 24, 2020

To make that minimal example work, you need to add #[serde(bound = "")] like this:

#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
struct TwoClosures<T> where
    T:'static
{
    inner: Option<TwoClosuresInner<T>>
}

Without it, serde is generating:

impl<T> Serialize for TwoClosures<T> where T: Serialize { ... }

Though as actually T itself is never serialized, the bound is unnecessary. Adding #[serde(bound = "")] makes serde generate this:

impl<T> Serialize for TwoClosures<T> { ... }

which then enables your program to compile.

@alecmocatta
Copy link
Owner

alecmocatta commented Jan 24, 2020

And second question: how to serialize struct TwoClosures by may hands without derive?

The serde guide to implementing Serialize and Deserialize are helpful here. The easiest way to serialize/deserialize them manually is as tuples.

@TrionProg
Copy link
Author

Hello. Hm.. It works! Thanks.

About Box in structures. What I should to use std::Box or s_to::Box? What is differense? Now it is using std::Box and it works, but maybe I should use s_to::Box. But how I remember I was unable to serialize std::Box manually.

@TrionProg
Copy link
Author

TrionProg commented Jan 26, 2020

Long live to new problems!

My manual serialization worked.

I am adding new generic M

pub trait BlockTrait<M:MyTrait>: SerializeTO + DeserializeTO{
    fn exec(&mut self, m:&mut M) -> bool;
}

pub trait MyTrait {}

struct TwoClosures<T, M> where
    T:'static,
    M:MyTrait + 'static
{
    inner: DataContainer<TwoClosuresInner<T, M>>
}

struct TwoClosuresInner<T, M> where
    T:'static,
    M:MyTrait + 'static
{
    a: BoxTO<FnOnceTO(&mut M) -> T>,
    b: BoxTO<FnOnceTO(T) -> bool>,
}

And I have this problem:

error[E0277]: the trait bound `dyn for<'r> serde_traitobject::FnOnce<(&'r mut M,), Output = T>: serde::Serialize` is not satisfied
   --> src\main.rs:107:32
    |
107 |         s.serialize_field("a", &inner.a)?;
    |                                ^^^^^^^^ the trait `serde::Serialize` is not implemented for `dyn for<'r> serde_traitobject::FnOnce<(&'r mut M,), Output = T>`
    |
    = help: the following implementations were found:
              <(dyn serde_traitobject::FnOnce<Args, Output = Output> + 'static) as serde::Serialize>
              <(dyn serde_traitobject::FnOnce<Args, Output = Output> + std::marker::Send + 'static) as serde::Serialize>
    = note: required because of the requirements on the impl of `serde::Serialize` for `std::boxed::Box<dyn for<'r> serde_traitobject::FnOnce<(&'r mut M,), Output = T>>`

And something about Deser.

The fragment of code:

impl<T,M> Serialize for TwoClosures<T,M> where
    //T:'static,
    M:MyTrait
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
    {
        use crate::serde::ser::SerializeStruct;

        let inner = self.inner.get();

        let mut s = serializer.serialize_struct("TwoClosures", 2)?;
        s.serialize_field("a", &inner.a)?;
        s.serialize_field("b", &inner.b)?;
        s.end()
    }
}

It may be solved by using BoxTO instead of Box, but without M it worked! Very strange...

And I want M to be Serial and Deserial -able. How to mark it in trait MyBlock or trait MyTrait ? Note: Other difficult code works by #derive , but I have problems with manual serialization

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants