use crate::{ config::{self, Config}, 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(src: &mut R) -> Result { decode_from_with_config(src, config::Default) } /// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. /// /// See the [config] module for more information about config options. pub fn decode_from_with_config( src: &mut R, _config: C, ) -> Result { let mut decoder = Decoder::<_, C>::new(src, _config); D::decode(&mut decoder) } impl<'storage, R: std::io::Read> Reader<'storage> for R { #[inline(always)] fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { match self.read_exact(bytes) { Ok(_) => Ok(()), Err(_) => Err(DecodeError::UnexpectedEnd), } } } /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`. pub fn encode_into_write( val: E, dst: &mut W, ) -> Result { encode_into_write_with_config(val, dst, config::Default) } /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information. 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, config); 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(()) } } impl<'a> Encodeable for &'a CStr { fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.to_bytes_with_nul().encode(encoder) } } impl<'de> BorrowDecodable<'de> for &'de CStr { fn borrow_decode>(decoder: D) -> Result { 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(&self, encoder: E) -> Result<(), EncodeError> { self.as_bytes_with_nul().encode(encoder) } } impl Decodable for CString { fn decode(decoder: D) -> Result { // BlockedTODO: https://github.com/rust-lang/rust/issues/73179 // use `from_vec_with_nul` instead, combined with: // let bytes = std::vec::Vec::::decode(decoder)?; // now we have to allocate twice unfortunately let vec: std::vec::Vec = std::vec::Vec::decode(decoder)?; let cstr = CStr::from_bytes_with_nul(&vec).map_err(|e| DecodeError::CStrNulError { inner: e })?; Ok(cstr.into()) } }