Skip to content

Commit

Permalink
Merge pull request #30 from alecmocatta/sc
Browse files Browse the repository at this point in the history
Add convenience traits for serde_closure::traits::*
  • Loading branch information
mergify[bot] authored Jul 14, 2020
2 parents 3a739ec + 57f3136 commit 677b67f
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 20 deletions.
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "serde_traitobject"
version = "0.2.6"
version = "0.2.7"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["development-tools","encoding","rust-patterns","network-programming"]
Expand All @@ -12,7 +12,7 @@ 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.6"
documentation = "https://docs.rs/serde_traitobject"
readme = "README.md"
edition = "2018"

Expand All @@ -25,12 +25,13 @@ serde = "1.0"
erased-serde = "0.3"
metatype = "0.2"
relative = "0.2"
serde_closure = { version = "0.3", optional = true }

[dev-dependencies]
bincode = "1.0"
serde_closure = "0.3"
serde_derive = "1.0"
serde_json = "1.0"
bincode = "1.0"
serde_closure = "0.2.2"
wasm-bindgen-test = "0.3"

[[test]]
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
[![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?definitionId=9)

[📖 Docs](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/) | [💬 Chat](https://constellation.zulipchat.com/#narrow/stream/213236-subprojects)
[📖 Docs](https://docs.rs/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.6/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.2.6/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/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.2/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.6/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/fn.deserialize.html) functions;
* The [Box](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.2.6/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/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.2/serde_traitobject/fn.deserialize.html) functions;
* The [Box](https://docs.rs/serde_traitobject/0.2/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.2/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.2/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.6/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.2.6/serde_traitobject/trait.FnOnce.html)
* [Any](https://docs.rs/serde_traitobject/0.2/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.2/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.2/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.2/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.2/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.2/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.2/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
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
endpoint: alecmocatta
default:
rust_toolchain: nightly
rust_lint_toolchain: nightly-2020-06-25
rust_lint_toolchain: nightly-2020-07-12
rust_flags: ''
rust_features: ''
rust_features: ';serde_closure'
rust_target_check: ''
rust_target_build: ''
rust_target_run: ''
Expand Down
186 changes: 181 additions & 5 deletions src/convenience.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ impl Box<dyn Any> {
self.0.into_any()
}
}
#[allow(clippy::use_self)]
impl Box<dyn Any + Send> {
/// Convert into a `std::boxed::Box<dyn std::any::Any + Send>`.
pub fn into_any_send(self) -> boxed::Box<dyn any::Any + Send> {
Expand All @@ -34,7 +33,6 @@ impl Box<dyn Any + Send> {
}
}
}
#[allow(clippy::use_self)]
impl Box<dyn Any + Sync> {
/// Convert into a `std::boxed::Box<dyn std::any::Any + Sync>`.
pub fn into_any_sync(self) -> boxed::Box<dyn any::Any + Sync> {
Expand All @@ -43,7 +41,6 @@ impl Box<dyn Any + Sync> {
}
}
}
#[allow(clippy::use_self)]
impl Box<dyn Any + Send + Sync> {
/// Convert into a `std::boxed::Box<dyn std::any::Any + Send + Sync>`.
pub fn into_any_send_sync(self) -> boxed::Box<dyn any::Any + Send + Sync> {
Expand Down Expand Up @@ -504,13 +501,11 @@ impl<'a> AsRef<Self> for dyn Error + Send + 'a {
}
}

#[allow(clippy::use_self)]
impl<'a, E: error::Error + Serialize + Deserialize + 'a> From<E> for Box<dyn Error + 'a> {
fn from(err: E) -> Self {
Box::new(err)
}
}
#[allow(clippy::use_self)]
impl<'a, E: error::Error + Serialize + Deserialize + 'a> From<E> for boxed::Box<dyn Error + 'a> {
fn from(err: E) -> Self {
boxed::Box::new(err)
Expand Down Expand Up @@ -858,3 +853,184 @@ impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
.map(|x| x.0)
}
}

/// Convenience traits implemented on all (de)serializable implementors of [`serde_closure::traits::*`](serde_closure::traits).
#[cfg(feature = "serde_closure")]
pub mod sc {
use super::{serialize, Box, Deserialize, Serialize};
use serde_closure::traits as sc;
use std::boxed;

/// A convenience trait implemented on all (de)serializable implementors of [`serde_closure::traits::FnOnce`].
///
/// It can be made into a trait object which is then (de)serializable.
pub trait FnOnce<Args>: sc::FnOnceBox<Args> + Serialize + Deserialize {}
impl<T: ?Sized, Args> FnOnce<Args> for T where T: sc::FnOnceBox<Args> + Serialize + Deserialize {}

impl<'a, Args, Output> AsRef<Self> for dyn FnOnce<Args, Output = Output> + 'a {
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, Args, Output> AsRef<Self> for dyn FnOnce<Args, 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>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn FnOnce<Args, Output = Output> + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn FnOnce<Args, Output = Output> + 'static>>::deserialize(deserializer)
.map(|x| x.0)
}
}
impl<Args: 'static, Output: 'static> serde::ser::Serialize
for dyn FnOnce<Args, Output = Output> + Send
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn FnOnce<Args, Output = Output> + Send + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn FnOnce<Args, Output = Output> + Send + 'static>>::deserialize(deserializer)
.map(|x| x.0)
}
}

/// A convenience trait implemented on all (de)serializable implementors of [`serde_closure::traits::FnMut`].
///
/// It can be made into a trait object which is then (de)serializable.
pub trait FnMut<Args>: sc::FnMut<Args> + Serialize + Deserialize {}
impl<T: ?Sized, Args> FnMut<Args> for T where T: sc::FnMut<Args> + Serialize + Deserialize {}

impl<'a, Args, Output> AsRef<Self> for dyn FnMut<Args, Output = Output> + 'a {
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, Args, Output> AsRef<Self> for dyn FnMut<Args, Output = Output> + Send + 'a {
fn as_ref(&self) -> &Self {
self
}
}

impl<Args: 'static, Output: 'static> serde::ser::Serialize for dyn FnMut<Args, Output = Output> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn FnMut<Args, Output = Output> + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn FnMut<Args, Output = Output> + 'static>>::deserialize(deserializer)
.map(|x| x.0)
}
}
impl<Args: 'static, Output: 'static> serde::ser::Serialize
for dyn FnMut<Args, Output = Output> + Send
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn FnMut<Args, Output = Output> + Send + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn FnMut<Args, Output = Output> + Send + 'static>>::deserialize(deserializer)
.map(|x| x.0)
}
}

/// A convenience trait implemented on all (de)serializable implementors of [`serde_closure::traits::Fn`].
///
/// It can be made into a trait object which is then (de)serializable.
pub trait Fn<Args>: sc::Fn<Args> + Serialize + Deserialize {}
impl<T: ?Sized, Args> Fn<Args> for T where T: sc::Fn<Args> + Serialize + Deserialize {}

impl<'a, Args, Output> AsRef<Self> for dyn Fn<Args, Output = Output> + 'a {
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, Args, Output> AsRef<Self> for dyn Fn<Args, Output = Output> + Send + 'a {
fn as_ref(&self) -> &Self {
self
}
}

impl<Args: 'static, Output: 'static> serde::ser::Serialize for dyn Fn<Args, Output = Output> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn Fn<Args, Output = Output> + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn Fn<Args, Output = Output> + 'static>>::deserialize(deserializer).map(|x| x.0)
}
}
impl<Args: 'static, Output: 'static> serde::ser::Serialize
for dyn Fn<Args, Output = Output> + Send
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize(self, serializer)
}
}
impl<'de, Args: 'static, Output: 'static> serde::de::Deserialize<'de>
for boxed::Box<dyn Fn<Args, Output = Output> + Send + 'static>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<Box<dyn Fn<Args, Output = Output> + Send + 'static>>::deserialize(deserializer)
.map(|x| x.0)
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
//!
//! This crate currently requires Rust nightly.

#![doc(html_root_url = "https://docs.rs/serde_traitobject/0.2.6")]
#![doc(html_root_url = "https://docs.rs/serde_traitobject/0.2.7")]
#![feature(
arbitrary_self_types,
coerce_unsized,
Expand Down
3 changes: 0 additions & 3 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,16 @@ trait Hello {
trait HelloSerialize: Hello + Serialize + Deserialize {}
impl<T> HelloSerialize for T where T: Hello + Serialize + Deserialize {}

#[allow(clippy::use_self)]
impl Hello for u32 {
fn hi(&self) -> String {
format!("hi u32! {:?}", self)
}
}
#[allow(clippy::use_self)]
impl Hello for u16 {
fn hi(&self) -> String {
format!("hi u16! {:?}", self)
}
}
#[allow(clippy::use_self)]
impl Hello for u8 {
fn hi(&self) -> String {
format!("hi u8! {:?}", self)
Expand Down

0 comments on commit 677b67f

Please sign in to comment.