Skip to content

Commit

Permalink
Merge pull request #27 from alecmocatta/hrtb-fn
Browse files Browse the repository at this point in the history
Workaround dyn Fn* with reference arguments (HRTB) not being (de)serializable
  • Loading branch information
mergify[bot] committed Jun 11, 2020
2 parents d1a59ff + 1ffab5d commit aa553ab
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 57 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "serde_traitobject"
version = "0.2.4"
version = "0.2.5"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["development-tools","encoding","rust-patterns","network-programming"]
Expand All @@ -12,12 +12,12 @@ This library enables the serialization and deserialization of trait objects such
"""
repository = "https://github.com/alecmocatta/serde_traitobject"
homepage = "https://github.com/alecmocatta/serde_traitobject"
documentation = "https://docs.rs/serde_traitobject/0.2.4"
documentation = "https://docs.rs/serde_traitobject/0.2.5"
readme = "README.md"
edition = "2018"

[badges]
azure-devops = { project = "alecmocatta/serde_traitobject", pipeline = "tests" }
azure-devops = { project = "alecmocatta/serde_traitobject", pipeline = "tests", build = "9" }
maintenance = { status = "actively-developed" }

[dependencies]
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

[![Crates.io](https://img.shields.io/crates/v/serde_traitobject.svg?maxAge=86400)](https://crates.io/crates/serde_traitobject)
[![MIT / Apache 2.0 licensed](https://img.shields.io/crates/l/serde_traitobject.svg?maxAge=2592000)](#License)
[![Build Status](https://dev.azure.com/alecmocatta/serde_traitobject/_apis/build/status/tests?branchName=master)](https://dev.azure.com/alecmocatta/serde_traitobject/_build/latest?branchName=master)
[![Build Status](https://dev.azure.com/alecmocatta/serde_traitobject/_apis/build/status/tests?branchName=master)](https://dev.azure.com/alecmocatta/serde_traitobject/_build?definitionId=9)

[Docs](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/)
[📖 Docs](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/) | [💬 Chat](https://constellation.zulipchat.com/#narrow/stream/213236-subprojects)

**Serializable and deserializable trait objects.**

This library enables the serialization and deserialization of trait objects so they can be sent between other processes running the same binary.

For example, if you have multiple forks of a process, or the same binary running on each of a cluster of machines, this library lets you send trait objects between them.

Any trait can be made (de)serializable when made into a trait object by adding this crate's [Serialize](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Deserialize.html) traits as supertraits:
Any trait can be made (de)serializable when made into a trait object by adding this crate's [Serialize](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Deserialize.html) traits as supertraits:

```rust
trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
Expand All @@ -31,12 +31,12 @@ struct Message {
And that's it! The two traits are automatically implemented for all `T: serde::Serialize` and all `T: serde::de::DeserializeOwned`, so as long as all implementors of your trait are themselves serializable then you're good to go.

There are two ways to (de)serialize your trait object:
* Apply the `#[serde(with = "serde_traitobject")]` [field attribute](https://serde.rs/attributes.html), which instructs serde to use this crate's [serialize](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/fn.deserialize.html) functions;
* The [Box](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/struct.Arc.html) structs, which are simple wrappers around their stdlib counterparts that automatically handle (de)serialization without needing the above annotation;
* Apply the `#[serde(with = "serde_traitobject")]` [field attribute](https://serde.rs/attributes.html), which instructs serde to use this crate's [serialize](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/fn.deserialize.html) functions;
* The [Box](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/struct.Arc.html) structs, which are simple wrappers around their stdlib counterparts that automatically handle (de)serialization without needing the above annotation;

Additionally, there are several convenience traits implemented that extend their stdlib counterparts:

* [Any](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.FnOnce.html)
* [Any](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.2.5/serde_traitobject/trait.FnOnce.html)

These are automatically implemented on all implementors of their stdlib counterparts that also implement `serde::Serialize` and `serde::de::DeserializeOwned`.

Expand Down
12 changes: 6 additions & 6 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ jobs:
endpoint: alecmocatta
default:
rust_toolchain: nightly
rust_lint_toolchain: nightly-2019-11-24
rust_lint_toolchain: nightly-2020-06-10
rust_flags: ''
rust_features: ''
rust_target_check: ''
rust_target_build: ''
rust_target_run: ''
matrix:
windows:
imageName: 'vs2017-win2016'
rust_target_run: 'x86_64-pc-windows-msvc i686-pc-windows-msvc' # currently broken building crate-type=lib: x86_64-pc-windows-gnu i686-pc-windows-gnu
imageName: 'windows-latest'
rust_target_run: 'x86_64-pc-windows-msvc i686-pc-windows-msvc x86_64-pc-windows-gnu'
mac:
imageName: 'macos-10.13'
rust_target_run: 'x86_64-apple-darwin i686-apple-darwin'
imageName: 'macos-latest'
rust_target_run: 'x86_64-apple-darwin'
linux:
imageName: 'ubuntu-16.04'
imageName: 'ubuntu-latest'
rust_target_run: 'x86_64-unknown-linux-gnu i686-unknown-linux-gnu x86_64-unknown-linux-musl i686-unknown-linux-musl wasm32-unknown-unknown'
71 changes: 63 additions & 8 deletions src/convenience.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::{deserialize, serialize, Deserialize, Serialize};
use serde;
use std::{
any, borrow::{Borrow, BorrowMut}, boxed, error, fmt, marker, ops::{self, Deref, DerefMut}, rc, sync
};

use super::{deserialize, serialize, Deserialize, Serialize};

/// Convenience wrapper around [std::boxed::Box<T>](std::boxed::Box) that automatically uses `serde_traitobject` for (de)serialization.
#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Box<T: ?Sized>(boxed::Box<T>);
Expand Down Expand Up @@ -128,6 +128,7 @@ impl<T> From<T> for Box<T> {
}
}
impl<T: error::Error> error::Error for Box<T> {
#[allow(deprecated)]
fn description(&self) -> &str {
error::Error::description(&**self)
}
Expand Down Expand Up @@ -472,14 +473,14 @@ impl<'de> serde::de::Deserialize<'de> for boxed::Box<dyn Any + Send + 'static> {
/// #[derive(Serialize,Deserialize,Debug)]
/// struct MyError(String);
/// impl fmt::Display for MyError {
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "{}", self.0)
/// }
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "{}", self.0)
/// }
/// }
/// impl std::error::Error for MyError {}
///
/// fn fallible() -> Result<(),s::Box<dyn s::Error>> {
/// Err(Box::new(MyError(String::from("boxed error"))) as Box<dyn s::Error>)?
/// Err(Box::new(MyError(String::from("boxed error"))) as Box<dyn s::Error>)?
/// }
///
/// let serialized = serde_json::to_string(&fallible()).unwrap();
Expand Down Expand Up @@ -561,7 +562,7 @@ impl<'de> serde::de::Deserialize<'de> for boxed::Box<dyn Error + Send + 'static>
/// extern crate serde_traitobject as s;
///
/// fn message() -> s::Box<dyn s::Display> {
/// s::Box::new(String::from("boxed displayable"))
/// s::Box::new(String::from("boxed displayable"))
/// }
///
/// let serialized = serde_json::to_string(&message()).unwrap();
Expand Down Expand Up @@ -630,7 +631,7 @@ impl<'de> serde::de::Deserialize<'de> for boxed::Box<dyn Display + Send + 'stati
/// extern crate serde_traitobject as s;
///
/// fn debug() -> s::Box<dyn s::Debug> {
/// s::Box::new(String::from("boxed debuggable"))
/// s::Box::new(String::from("boxed debuggable"))
/// }
///
/// let serialized = serde_json::to_string(&debug()).unwrap();
Expand Down Expand Up @@ -703,6 +704,16 @@ impl<'a, Args, Output> AsRef<Self> for dyn FnOnce<Args, Output = Output> + Send
self
}
}
impl<'a, A, Output> AsRef<Self> for dyn for<'r> FnOnce<(&'r A,), Output = Output> + 'a {
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, A, Output> AsRef<Self> for dyn for<'r> FnOnce<(&'r A,), Output = Output> + Send + 'a {
fn as_ref(&self) -> &Self {
self
}
}

impl<Args: 'static, Output: 'static> serde::ser::Serialize for dyn FnOnce<Args, Output = Output> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down Expand Up @@ -743,6 +754,50 @@ impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
.map(|x| x.0)
}
}
impl<A: 'static, Output: 'static> serde::ser::Serialize
for dyn for<'r> FnOnce<(&'r A,), Output = Output>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, A: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn for<'r> FnOnce<(&'r A,), Output = Output> + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn for<'r> FnOnce<(&'r A,), Output = Output> + 'static>>::deserialize(deserializer)
.map(|x| x.0)
}
}
impl<A: 'static, Output: 'static> serde::ser::Serialize
for dyn for<'r> FnOnce<(&'r A,), Output = Output> + Send
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, A: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn for<'r> FnOnce<(&'r A,), Output = Output> + Send + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn for<'r> FnOnce<(&'r A,), Output = Output> + Send + 'static>>::deserialize(
deserializer,
)
.map(|x| x.0)
}
}

/// A convenience trait implemented on all (de)serializable implementors of [`std::ops::FnMut`].
///
Expand Down
Loading

0 comments on commit aa553ab

Please sign in to comment.