Added support for CStr and CString

This commit is contained in:
Victor Koenders 2021-10-16 12:59:38 +02:00
parent a322e0f1b3
commit 33dd4f761d
4 changed files with 63 additions and 14 deletions

View File

@ -71,6 +71,13 @@ pub enum DecodeError {
/// The length of the array found in the binary format.
found: usize,
},
/// The decoder tried to decode a `CStr` or `CString`, but the incoming data contained a 0 byte
#[cfg(feature = "std")]
CStrNulError {
/// The inner exception
inner: std::ffi::FromBytesWithNulError,
},
}
/// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors.

View File

@ -1,9 +1,10 @@
use crate::{
config::{self, Config},
de::{read::Reader, Decodable, Decoder},
enc::{write::Writer, Encodeable, Encoder},
de::{read::Reader, BorrowDecodable, BorrowDecode, Decodable, Decode, Decoder},
enc::{write::Writer, Encode, Encodeable, Encoder},
error::{DecodeError, EncodeError},
};
use std::ffi::{CStr, CString};
/// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
pub fn decode_from<D: Decodable, R: std::io::Read>(src: &mut R) -> Result<D, DecodeError> {
@ -71,3 +72,36 @@ impl<'storage, W: std::io::Write> Writer for IoWriter<'storage, W> {
Ok(())
}
}
impl<'a> Encodeable for &'a CStr {
fn encode<E: Encode>(&self, encoder: E) -> Result<(), EncodeError> {
self.to_bytes_with_nul().encode(encoder)
}
}
impl<'de> BorrowDecodable<'de> for &'de CStr {
fn borrow_decode<D: BorrowDecode<'de>>(decoder: D) -> Result<Self, DecodeError> {
let bytes = <&[u8]>::borrow_decode(decoder)?;
CStr::from_bytes_with_nul(bytes).map_err(|e| DecodeError::CStrNulError { inner: e })
}
}
impl Encodeable for CString {
fn encode<E: Encode>(&self, encoder: E) -> Result<(), EncodeError> {
self.as_bytes_with_nul().encode(encoder)
}
}
impl Decodable for CString {
fn decode<D: Decode>(decoder: D) -> Result<Self, DecodeError> {
// BlockedTODO: https://github.com/rust-lang/rust/issues/73179
// use `from_vec_with_nul` instead, combined with:
// let bytes = std::vec::Vec::<u8>::decode(decoder)?;
// now we have to allocate twice unfortunately
let vec: std::vec::Vec<u8> = std::vec::Vec::decode(decoder)?;
let cstr =
CStr::from_bytes_with_nul(&vec).map_err(|e| DecodeError::CStrNulError { inner: e })?;
Ok(cstr.into())
}
}

View File

@ -1,5 +1,9 @@
#![cfg(feature = "std")]
mod utils;
use utils::the_same;
struct Foo {
pub a: u32,
pub b: u32,
@ -49,3 +53,17 @@ fn test_std_file() {
assert_eq!(foo.a, 30);
assert_eq!(foo.b, 50);
}
#[test]
fn test_std_commons() {
use std::ffi::{CStr, CString};
the_same(CString::new("Hello world").unwrap());
let config = bincode::config::Default;
let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap();
let mut buffer = [0u8; 1024];
let len = bincode::encode_into_slice_with_config(cstr, &mut buffer, config).unwrap();
let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap();
assert_eq!(cstr, decoded);
}

View File

@ -3,12 +3,7 @@ use core::fmt::Debug;
fn the_same_with_config<V, C>(element: V, config: C)
where
V: bincode::enc::Encodeable
+ for<'de> bincode::de::Decodable
+ PartialEq
+ Debug
+ Clone
+ 'static,
V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static,
C: Config,
{
let mut buffer = [0u8; 1024];
@ -26,12 +21,7 @@ where
pub fn the_same<V>(element: V)
where
V: bincode::enc::Encodeable
+ for<'de> bincode::de::Decodable
+ PartialEq
+ Debug
+ Clone
+ 'static,
V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static,
{
// A matrix of each different config option possible
the_same_with_config(