Skip to content

Commit

Permalink
Merge pull request #19 from alecmocatta/leak
Browse files Browse the repository at this point in the history
Use pointer rather than reference to adhere to unsafe guidelines
  • Loading branch information
mergify[bot] authored Oct 16, 2019
2 parents c4d0310 + 013dedf commit f1d9f03
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 40 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "serde_traitobject"
version = "0.1.7"
version = "0.1.8"
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.1.7"
documentation = "https://docs.rs/serde_traitobject/0.1.8"
readme = "README.md"
edition = "2018"

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/latest?branchName=master)

[Docs](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/)
[Docs](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/)

**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.1.7/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.1.7/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.1.8/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.Deserialize.html) traits as supertraits:

```rust
trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
Expand All @@ -28,12 +28,12 @@ struct Message(#[serde(with = "serde_traitobject")] Box<dyn MyTrait>);
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.1.7/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/fn.deserialize.html) functions;
* The [Box](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.1.7/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.1.8/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/fn.deserialize.html) functions;
* The [Box](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.1.8/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.1.7/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.1.7/serde_traitobject/trait.FnOnce.html)
* [Any](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.1.8/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.1.8/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
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
endpoint: alecmocatta
default:
rust_toolchain: nightly
rust_lint_toolchain: nightly-2019-08-15
rust_lint_toolchain: nightly-2019-10-15
rust_flags: ''
rust_features: ''
rust_target_check: ''
Expand Down
46 changes: 14 additions & 32 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! # fn main() {
//! trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
//! fn my_method(&self);
//! }
Expand All @@ -19,7 +18,6 @@
//! struct Message(#[serde(with = "serde_traitobject")] Box<dyn MyTrait>);
//!
//! // Woohoo, `Message` is now serializable!
//! # }
//! ```
//!
//! 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.
Expand All @@ -36,7 +34,6 @@
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! # fn main() {
//! use std::any::Any;
//! use serde_traitobject as s;
//!
Expand All @@ -61,7 +58,6 @@
//! println!("{:?}", downcast);
//! # assert_eq!(format!("{:?}", downcast), "MyStruct { foo: \"abc\", bar: 123 }");
//! // MyStruct { foo: "abc", bar: 123 }
//! # }
//! ```
//!
//! # Security
Expand Down Expand Up @@ -98,8 +94,9 @@
//!
//! This crate currently requires Rust nightly.

#![doc(html_root_url = "https://docs.rs/serde_traitobject/0.1.7")]
#![doc(html_root_url = "https://docs.rs/serde_traitobject/0.1.8")]
#![feature(
arbitrary_self_types,
coerce_unsized,
core_intrinsics,
fn_traits,
Expand Down Expand Up @@ -138,32 +135,27 @@ pub use convenience::*;
/// ```
/// use serde_derive::{Serialize, Deserialize};
///
/// # fn main() {
/// trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
/// fn my_method(&self);
/// }
/// # }
/// ```
///
/// Now your trait object is serializable!
/// ```
/// # use serde_derive::{Serialize, Deserialize};
/// #
/// # fn main() {
/// # trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
/// # fn my_method(&self);
/// # }
/// #[derive(Serialize, Deserialize)]
/// struct Message(#[serde(with = "serde_traitobject")] Box<dyn MyTrait>);
///
/// // Woohoo, `Message` is now serializable!
/// # }
/// ```
///
/// Any implementers of `MyTrait` would now have to themselves implement `serde::Serialize` and `serde::de::DeserializeOwned`. This would typically be through `serde_derive`, like:
/// ```
/// # use serde_derive::{Serialize, Deserialize};
/// # fn main() {
/// # trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
/// # fn my_method(&self);
/// # }
Expand All @@ -179,7 +171,6 @@ pub use convenience::*;
/// println!("foo: {}", self.foo);
/// }
/// }
/// # }
/// ```
pub trait Serialize: serialize::Sealed {}
impl<T: serde::ser::Serialize + ?Sized> Serialize for T {}
Expand All @@ -192,32 +183,27 @@ impl<T: serde::ser::Serialize + ?Sized> Serialize for T {}
/// ```
/// use serde_derive::{Serialize, Deserialize};
///
/// # fn main() {
/// trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
/// fn my_method(&self);
/// }
/// # }
/// ```
///
/// Now your trait object is serializable!
/// ```
/// # use serde_derive::{Serialize, Deserialize};
/// #
/// # fn main() {
/// # trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
/// # fn my_method(&self);
/// # }
/// #[derive(Serialize, Deserialize)]
/// struct Message(#[serde(with = "serde_traitobject")] Box<dyn MyTrait>);
///
/// // Woohoo, `Message` is now serializable!
/// # }
/// ```
///
/// Any implementers of `MyTrait` would now have to themselves implement `serde::Serialize` and `serde::de::DeserializeOwned`. This would typically be through `serde_derive`, like:
/// ```
/// # use serde_derive::{Serialize, Deserialize};
/// # fn main() {
/// # trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize {
/// # fn my_method(&self);
/// # }
Expand All @@ -233,7 +219,6 @@ impl<T: serde::ser::Serialize + ?Sized> Serialize for T {}
/// println!("foo: {}", self.foo);
/// }
/// }
/// # }
/// ```
pub trait Deserialize: deserialize::Sealed {}
impl<T: serde::de::DeserializeOwned> Deserialize for T {}
Expand Down Expand Up @@ -283,7 +268,7 @@ mod deserialize {
/// Unsafe as it `ptr::write`s into `&mut self`, assuming it to be uninitialized
#[inline(always)]
unsafe fn deserialize_erased(
&mut self, deserializer: &mut dyn erased_serde::Deserializer,
self: *mut Self, deserializer: &mut dyn erased_serde::Deserializer,
) -> Result<(), erased_serde::Error> {
let _ = deserializer;
unreachable!()
Expand All @@ -308,7 +293,7 @@ mod deserialize {
impl<T: serde::de::DeserializeOwned> Sealed for T {
#[inline(always)]
unsafe fn deserialize_erased(
&mut self, deserializer: &mut dyn erased_serde::Deserializer,
self: *mut Self, deserializer: &mut dyn erased_serde::Deserializer,
) -> Result<(), erased_serde::Error> {
erased_serde::deserialize(deserializer).map(|x| ptr::write(self, x))
}
Expand Down Expand Up @@ -453,7 +438,7 @@ impl<T: Deserialize + ?Sized + 'static> DeserializerTrait<T> for Deserializer<T>
});
let t1: u64 = match seq.next_element()? {
Some(value) => value,
None => return Err(serde::de::Error::invalid_length(1, &self)),
None => return Err(serde::de::Error::invalid_length(1, &self)), // TODO: don't leak uninitialized box
};
assert_eq!(t1, object.type_id(), "Deserializing the trait object \"{}\" failed in a way that should never happen. Please file an issue! https://github.com/alecmocatta/serde_traitobject/issues/new", type_name::<T>());
let t2: boxed::Box<T> = match seq
Expand All @@ -477,11 +462,16 @@ impl<'de, T: Deserialize + ?Sized> serde::de::DeserializeSeed<'de> for Deseriali
D: serde::de::Deserializer<'de>,
{
let mut x = self.0;
unsafe {
(&mut *x).deserialize_erased(&mut erased_serde::Deserializer::erase(deserializer))
let x_ptr: *mut T = &mut *x;
match unsafe {
x_ptr.deserialize_erased(&mut erased_serde::Deserializer::erase(deserializer))
} {
Ok(()) => Ok(x),
Err(err) => {
mem::forget(x); // TODO: don't leak uninitialized box
Err(serde::de::Error::custom(err))
}
}
.map(|()| x)
.map_err(serde::de::Error::custom)
}
}

Expand All @@ -491,26 +481,22 @@ impl<'de, T: Deserialize + ?Sized> serde::de::DeserializeSeed<'de> for Deseriali
/// ```
/// # use serde_derive::{Serialize, Deserialize};
///
/// # fn main() {
/// #[derive(Serialize, Deserialize)]
/// struct MyStruct {
/// #[serde(with = "serde_traitobject")]
/// field: Box<dyn serde_traitobject::Any>,
/// }
/// # }
/// ```
///
/// Or, alternatively, if only Serialize is desired:
/// ```
/// # use serde_derive::{Serialize, Deserialize};
///
/// # fn main() {
/// #[derive(Serialize)]
/// struct MyStruct {
/// #[serde(serialize_with = "serde_traitobject::serialize")]
/// field: Box<dyn serde_traitobject::Any>,
/// }
/// # }
/// ```
pub fn serialize<T: Serialize + ?Sized + 'static, B: AsRef<T> + ?Sized, S>(
t: &B, serializer: S,
Expand All @@ -527,26 +513,22 @@ where
/// ```
/// # use serde_derive::{Serialize, Deserialize};
///
/// # fn main() {
/// #[derive(Serialize, Deserialize)]
/// struct MyStruct {
/// #[serde(with = "serde_traitobject")]
/// field: Box<dyn serde_traitobject::Any>,
/// }
/// # }
/// ```
///
/// Or, alternatively, if only Deserialize is desired:
/// ```
/// # use serde_derive::{Serialize, Deserialize};
///
/// # fn main() {
/// #[derive(Deserialize)]
/// struct MyStruct {
/// #[serde(deserialize_with = "serde_traitobject::deserialize")]
/// field: Box<dyn serde_traitobject::Any>,
/// }
/// # }
/// ```
pub fn deserialize<'de, T: Deserialize + ?Sized + 'static, B, D>(
deserializer: D,
Expand Down
1 change: 1 addition & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl Hello for u8 {
}
}

#[allow(clippy::too_many_lines)]
fn main() {
let test = |Abc {
a,
Expand Down

0 comments on commit f1d9f03

Please sign in to comment.