diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6697b3e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*] +tab_width = 4 + +[.*] +tab_width = 4 diff --git a/Cargo.toml b/Cargo.toml index aed5aa0..a4beb56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_traitobject" -version = "0.2.3" +version = "0.2.4" license = "MIT OR Apache-2.0" authors = ["Alec Mocatta "] categories = ["development-tools","encoding","rust-patterns","network-programming"] @@ -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.3" +documentation = "https://docs.rs/serde_traitobject/0.2.4" readme = "README.md" edition = "2018" @@ -31,6 +31,7 @@ serde_derive = "1.0" serde_json = "1.0" bincode = "1.0" serde_closure = "0.2.2" +wasm-bindgen-test = "0.3" [[test]] name = "test" diff --git a/README.md b/README.md index 32e73d5..2f7d1c2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![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.2.3/serde_traitobject/) +[Docs](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/) **Serializable and deserializable trait objects.** @@ -12,15 +12,18 @@ This library enables the serialization and deserialization of trait objects so t 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.3/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.2.3/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.4/serde_traitobject/trait.Serialize.html) and [Deserialize](https://docs.rs/serde_traitobject/0.2.4/serde_traitobject/trait.Deserialize.html) traits as supertraits: ```rust trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize { - fn my_method(&self); + fn my_method(&self); } #[derive(Serialize, Deserialize)] -struct Message(#[serde(with = "serde_traitobject")] Box); +struct Message { + #[serde(with = "serde_traitobject")] + message: Box, +} // Woohoo, `Message` is now serializable! ``` @@ -28,12 +31,12 @@ struct Message(#[serde(with = "serde_traitobject")] Box); 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.3/serde_traitobject/fn.serialize.html) and [deserialize](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/fn.deserialize.html) functions; - * The [Box](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/struct.Box.html), [Rc](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/struct.Rc.html) and [Arc](https://docs.rs/serde_traitobject/0.2.3/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.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; Additionally, there are several convenience traits implemented that extend their stdlib counterparts: - * [Any](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.Any.html), [Debug](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.Debug.html), [Display](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.Display.html), [Error](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.Error.html), [Fn](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.Fn.html), [FnMut](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.FnMut.html), [FnOnce](https://docs.rs/serde_traitobject/0.2.3/serde_traitobject/trait.FnOnce.html) + * [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) These are automatically implemented on all implementors of their stdlib counterparts that also implement `serde::Serialize` and `serde::de::DeserializeOwned`. @@ -43,13 +46,13 @@ use serde_traitobject as s; #[derive(Serialize, Deserialize, Debug)] struct MyStruct { - foo: String, - bar: usize, + foo: String, + bar: usize, } let my_struct = MyStruct { - foo: String::from("abc"), - bar: 123, + foo: String::from("abc"), + bar: 123, }; let erased: s::Box = s::Box::new(my_struct); @@ -69,6 +72,8 @@ This crate works by wrapping the vtable pointer with [`relative::Vtable`](https: This approach is not yet secure against malicious actors. However, if we assume non-malicious actors and typical (static or dynamic) linking conditions, then it's not unreasonable to consider it sound. +See [here](https://github.com/rust-lang/rust/pull/66113) for ongoing work in `rustc` to make this safe and secure. + ### Validation Three things are serialized alongside the vtable pointer for the purpose of validation: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c2fbdfe..ef42450 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,7 +14,7 @@ jobs: endpoint: alecmocatta default: rust_toolchain: nightly - rust_lint_toolchain: nightly-2019-10-17 + rust_lint_toolchain: nightly-2019-11-24 rust_flags: '' rust_features: '' rust_target_check: '' @@ -29,4 +29,4 @@ jobs: rust_target_run: 'x86_64-apple-darwin i686-apple-darwin' linux: imageName: 'ubuntu-16.04' - rust_target_run: 'x86_64-unknown-linux-gnu i686-unknown-linux-gnu x86_64-unknown-linux-musl i686-unknown-linux-musl' + rust_target_run: 'x86_64-unknown-linux-gnu i686-unknown-linux-gnu x86_64-unknown-linux-musl i686-unknown-linux-musl wasm32-unknown-unknown' diff --git a/src/convenience.rs b/src/convenience.rs index 04a3b0d..65c630c 100644 --- a/src/convenience.rs +++ b/src/convenience.rs @@ -52,6 +52,24 @@ impl Box { } } } +impl dyn Any + Send { + /// Convert into a `std::boxed::Box`. + pub fn into_any_send(self: boxed::Box) -> boxed::Box { + >::into_any_send(Box(self)) + } +} +impl dyn Any + Sync { + /// Convert into a `std::boxed::Box`. + pub fn into_any_sync(self: boxed::Box) -> boxed::Box { + >::into_any_sync(Box(self)) + } +} +impl dyn Any + Send + Sync { + /// Convert into a `std::boxed::Box`. + pub fn into_any_send_sync(self: boxed::Box) -> boxed::Box { + >::into_any_send_sync(Box(self)) + } +} impl, U: ?Sized> ops::CoerceUnsized> for Box {} impl Deref for Box { type Target = boxed::Box; diff --git a/src/lib.rs b/src/lib.rs index 489a628..132da32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,11 +11,14 @@ //! ``` //! # use serde_derive::{Serialize, Deserialize}; //! trait MyTrait: serde_traitobject::Serialize + serde_traitobject::Deserialize { -//! fn my_method(&self); +//! fn my_method(&self); //! } //! //! #[derive(Serialize, Deserialize)] -//! struct Message(#[serde(with = "serde_traitobject")] Box); +//! struct Message { +//! #[serde(with = "serde_traitobject")] +//! message: Box, +//! } //! //! // Woohoo, `Message` is now serializable! //! ``` @@ -39,13 +42,13 @@ //! //! #[derive(Serialize, Deserialize, Debug)] //! struct MyStruct { -//! foo: String, -//! bar: usize, +//! foo: String, +//! bar: usize, //! } //! //! let my_struct = MyStruct { -//! foo: String::from("abc"), -//! bar: 123, +//! foo: String::from("abc"), +//! bar: 123, //! }; //! //! let erased: s::Box = s::Box::new(my_struct); @@ -66,6 +69,8 @@ //! //! This approach is not yet secure against malicious actors. However, if we assume non-malicious actors and typical (static or dynamic) linking conditions, then it's not unreasonable to consider it sound. //! +//! See [here](https://github.com/rust-lang/rust/pull/66113) for ongoing work in `rustc` to make this safe and secure. +//! //! ## Validation //! //! Three things are serialized alongside the vtable pointer for the purpose of validation: @@ -94,7 +99,7 @@ //! //! This crate currently requires Rust nightly. -#![doc(html_root_url = "https://docs.rs/serde_traitobject/0.2.3")] +#![doc(html_root_url = "https://docs.rs/serde_traitobject/0.2.4")] #![feature( arbitrary_self_types, coerce_unsized, diff --git a/tests/test.rs b/tests/test.rs index 1b01d37..e670af4 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -16,6 +16,7 @@ use serde_closure::Fn; use serde_derive::{Deserialize, Serialize}; use serde_traitobject::{Deserialize, Serialize}; use std::{any, env, process, rc}; +use wasm_bindgen_test::wasm_bindgen_test; #[derive(Serialize, Deserialize)] struct Abc { @@ -87,6 +88,7 @@ impl<'a> AsRef for dyn Hello2Serialize { } } +#[wasm_bindgen_test] #[allow(clippy::too_many_lines)] fn main() { let test = |Abc { @@ -223,6 +225,10 @@ fn main() { o: vec![1u16, 2, 3].into(), }; + if cfg!(target_arch = "wasm32") { + return; + } + if let Ok(x) = env::var("SERDE_TRAITOBJECT_SPAWNED") { let (a, bc): (_, Vec) = serde_json::from_str(&x).unwrap(); eq(&original, &a);