diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cc3ba9..148c41a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.1.0] - 2023-09-20 + +### ADDED + +- Added support for [Bincode](https://docs.rs/bincode/2.0.0-rc.3/bincode/). Use `bincode` + feature to enable it. + ## [1.0.1] - 2022-03-24 ### FIXED diff --git a/Cargo.toml b/Cargo.toml index 69b3aac..f11ef34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smartstring" -version = "1.0.1" +version = "1.1.0" authors = ["Bodil Stokke "] edition = "2021" license = "MPL-2.0+" @@ -15,7 +15,7 @@ rust-version = "1.57" build = "./build.rs" [package.metadata.docs.rs] -features = ["arbitrary", "proptest", "serde"] +features = ["arbitrary", "proptest", "serde", "bincode"] [badges] travis-ci = { repository = "bodil/smartstring", branch = "master" } @@ -25,15 +25,17 @@ name = "smartstring" harness = false [features] -default = ["std"] +default = ["std", "bincode"] std = [] test = ["std", "arbitrary", "arbitrary/derive"] +bincode = ["dep:bincode"] [dependencies] static_assertions = "1" serde = { version = "1", optional = true } arbitrary = { version = "1", optional = true } proptest = { version = "1", optional = true } +bincode = { version = "2.0.1", features=["alloc"], optional = true } [dev-dependencies] proptest = "1" diff --git a/build.rs b/build.rs index fb8ca0c..8265f87 100644 --- a/build.rs +++ b/build.rs @@ -5,9 +5,12 @@ use version_check as rustc; fn main() { + println!("cargo:rustc-check-cfg=cfg(needs_allocator_feature)"); + println!("cargo:rustc-check-cfg=cfg(has_allocator)"); + let ac = autocfg::new(); let has_feature = Some(true) == rustc::supports_feature("allocator_api"); - let has_api = ac.probe_trait("alloc::alloc::Allocator"); + let has_api = ac.probe_trait("core::alloc::GlobalAlloc"); if has_feature || has_api { autocfg::emit("has_allocator"); } diff --git a/src/bincode.rs b/src/bincode.rs new file mode 100644 index 0000000..47c2edf --- /dev/null +++ b/src/bincode.rs @@ -0,0 +1,83 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Support for Bincode integration. Enable this with the `bincode` feature. + +use crate::{Compact, LazyCompact, SmartString, SmartStringMode, MAX_INLINE}; +use std::ops::Deref; + +use bincode::{ + de::Decoder, + enc::Encoder, + error::{DecodeError, EncodeError}, + impl_borrow_decode, Decode, Encode, +}; + +impl Encode for SmartString { + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_bytes().encode(encoder) + } +} + +impl Decode for SmartString { + fn decode>(decoder: &mut D) -> Result { + let bytes: Vec = as Decode>::decode(decoder)?; + let string = String::from_utf8(bytes).map_err(|e| DecodeError::Utf8 { + inner: e.utf8_error(), + })?; + Ok(if string.len() > MAX_INLINE { + Self::from_boxed(string.into()) + } else { + Self::from_inline(string.deref().into()) + }) + } +} + +impl_borrow_decode!(SmartString); +impl_borrow_decode!(SmartString); + +#[cfg(test)] +mod test { + use crate::{Compact, LazyCompact, SmartString}; + + #[test] + fn test_bincode_compact() { + let mut buf: [u8; 64] = [0; 64]; + let short_str = "Hello world"; + let long_str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + let config = bincode::config::standard(); + let smartstring = SmartString::::from(short_str); + let len = bincode::encode_into_slice(smartstring, &mut buf, config).unwrap(); + let smartstring: SmartString = + bincode::decode_from_slice(&buf[..len], config).unwrap().0; + assert_eq!(smartstring, short_str); + + let smartstring = SmartString::::from(long_str); + let len = bincode::encode_into_slice(smartstring, &mut buf, config).unwrap(); + let smartstring: SmartString = + bincode::decode_from_slice(&buf[..len], config).unwrap().0; + assert_eq!(smartstring, long_str); + } + + #[test] + fn test_bincode_lazy_compact() { + let mut buf: [u8; 64] = [0; 64]; + let short_str = "Hello world"; + let long_str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + let config = bincode::config::standard(); + let smartstring = SmartString::::from(short_str); + let len = bincode::encode_into_slice(smartstring, &mut buf, config).unwrap(); + let smartstring: SmartString = + bincode::decode_from_slice(&buf[..len], config).unwrap().0; + assert_eq!(smartstring, short_str); + + let smartstring = SmartString::::from(long_str); + let len = bincode::encode_into_slice(smartstring, &mut buf, config).unwrap(); + let smartstring: SmartString = + bincode::decode_from_slice(&buf[..len], config).unwrap().0; + assert_eq!(smartstring, long_str); + } +} diff --git a/src/lib.rs b/src/lib.rs index 33e0023..80fcb4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,7 +82,7 @@ //! //! ```no_compile //! [dependencies] -//! smartstring = { version = "*", features = ["proptest", "serde"] } +//! smartstring = { version = "*", features = ["proptest", "serde", "bincode"] } //! ``` //! //! | Feature | Description | @@ -90,9 +90,12 @@ //! | [`arbitrary`](https://crates.io/crates/arbitrary) | [`Arbitrary`][Arbitrary] implementation for [`SmartString`]. | //! | [`proptest`](https://crates.io/crates/proptest) | A strategy for generating [`SmartString`]s from a regular expression. | //! | [`serde`](https://crates.io/crates/serde) | [`Serialize`][Serialize] and [`Deserialize`][Deserialize] implementations for [`SmartString`]. | +//! | [`bincode`](https://crates.io/crates/bincode) | [`Encode`][Encode] and [`Decode`][Decode] implementations for [`SmartString`]. | //! //! [Serialize]: https://docs.rs/serde/latest/serde/trait.Serialize.html //! [Deserialize]: https://docs.rs/serde/latest/serde/trait.Deserialize.html +//! [Encode]: https://docs.rs/bincode/2.0.0-rc.3/bincode/enc/trait.Encode.html +//! [Decode]: https://docs.rs/bincode/2.0.0-rc.3/bincode/de/trait.Decode.html //! [Arbitrary]: https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html // Ensure all unsafe blocks get flagged for manual validation. @@ -159,6 +162,9 @@ mod arbitrary; #[cfg(feature = "proptest")] pub mod proptest; +#[cfg(feature = "bincode")] +mod bincode; + /// Convenient type aliases. pub mod alias { use super::*;