diff --git a/Cargo.toml b/Cargo.toml index c188eb1..2fc5727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,4 @@ serde = { version = "1.0.130", optional = true } [dev-dependencies] serde_derive = "1.0.130" serde_json = "1.0.68" +tempfile = "3.2.0" diff --git a/src/error.rs b/src/error.rs index 04db286..b21c6df 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,12 @@ pub enum EncodeError { InvalidIntEncoding, UnexpectedEnd, + + #[cfg(feature = "std")] + Io { + error: std::io::Error, + index: usize, + }, } #[non_exhaustive] diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 31d9758..0cdca00 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -1,7 +1,8 @@ use crate::{ config::{self, Config}, de::{read::Reader, Decodable, Decoder}, - error::DecodeError, + enc::{write::Writer, Encodeable, Encoder}, + error::{DecodeError, EncodeError}, }; pub fn decode_from(src: &mut R) -> Result { @@ -25,3 +26,42 @@ impl<'storage, R: std::io::Read> Reader<'storage> for R { } } } + +pub fn encode_into_write( + val: E, + dst: &mut W, +) -> Result { + encode_into_write_with_config(val, dst, config::Default) +} + +pub fn encode_into_write_with_config( + val: E, + dst: &mut W, + _config: C, +) -> Result { + let writer = IoWriter { + writer: dst, + bytes_written: 0, + }; + let mut encoder = Encoder::<_, C>::new(writer); + val.encode(&mut encoder)?; + Ok(encoder.into_writer().bytes_written) +} + +struct IoWriter<'a, W: std::io::Write> { + writer: &'a mut W, + bytes_written: usize, +} + +impl<'storage, W: std::io::Write> Writer for IoWriter<'storage, W> { + fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> { + self.writer + .write_all(bytes) + .map_err(|error| EncodeError::Io { + error, + index: self.bytes_written, + })?; + self.bytes_written += bytes.len(); + Ok(()) + } +} diff --git a/tests/alloc.rs b/tests/alloc.rs new file mode 100644 index 0000000..1dee965 --- /dev/null +++ b/tests/alloc.rs @@ -0,0 +1,36 @@ +#![cfg(feature = "alloc")] + +struct Foo { + pub a: u32, + pub b: u32, +} + +impl bincode::enc::Encodeable for Foo { + fn encode( + &self, + mut encoder: E, + ) -> Result<(), bincode::error::EncodeError> { + self.a.encode(&mut encoder)?; + self.b.encode(&mut encoder)?; + Ok(()) + } +} + +impl bincode::de::Decodable for Foo { + fn decode(mut decoder: D) -> Result { + Ok(Self { + a: bincode::de::Decodable::decode(&mut decoder)?, + b: bincode::de::Decodable::decode(&mut decoder)?, + }) + } +} + +#[test] +fn test_vec() { + let vec = bincode::encode_to_vec(Foo { a: 5, b: 10 }).unwrap(); + assert_eq!(vec, &[5, 10]); + + let foo: Foo = bincode::decode(&vec).unwrap(); + assert_eq!(foo.a, 5); + assert_eq!(foo.b, 10); +} diff --git a/tests/std.rs b/tests/std.rs new file mode 100644 index 0000000..da8b984 --- /dev/null +++ b/tests/std.rs @@ -0,0 +1,51 @@ +#![cfg(feature = "std")] + +struct Foo { + pub a: u32, + pub b: u32, +} + +impl bincode::enc::Encodeable for Foo { + fn encode( + &self, + mut encoder: E, + ) -> Result<(), bincode::error::EncodeError> { + self.a.encode(&mut encoder)?; + self.b.encode(&mut encoder)?; + Ok(()) + } +} + +impl bincode::de::Decodable for Foo { + fn decode(mut decoder: D) -> Result { + Ok(Self { + a: bincode::de::Decodable::decode(&mut decoder)?, + b: bincode::de::Decodable::decode(&mut decoder)?, + }) + } +} + +#[test] +fn test_std_cursor() { + let mut cursor = std::io::Cursor::<&[u8]>::new(&[5, 10]); + let foo: Foo = bincode::decode_from(&mut cursor).unwrap(); + + assert_eq!(foo.a, 5); + assert_eq!(foo.b, 10); +} + +#[test] +fn test_std_file() { + use std::io::{Seek, SeekFrom}; + + let mut file = tempfile::tempfile().expect("Could not create temp file"); + + let bytes_written = bincode::encode_into_write(Foo { a: 30, b: 50 }, &mut file).unwrap(); + assert_eq!(bytes_written, 2); + file.seek(SeekFrom::Start(0)).unwrap(); + + let foo: Foo = bincode::decode_from(&mut file).unwrap(); + + assert_eq!(foo.a, 30); + assert_eq!(foo.b, 50); +}