diff --git a/src/pod.rs b/src/pod.rs index 42737d1c..119675b0 100644 --- a/src/pod.rs +++ b/src/pod.rs @@ -9,7 +9,6 @@ )] use alloc::string::String; -use alloc::vec::Vec; use core::{fmt, mem, result, slice}; type Result = result::Result; @@ -308,90 +307,7 @@ impl<'data> Bytes<'data> { } } -/// Trait for writable buffer. -pub trait WritableBuffer { - /// Returns position/offset for data to be written at. - fn len(&self) -> usize; - /// Returns true if buffer contains no data. - fn is_empty(&self) -> bool; - /// Reserves specified number of bytes in the buffer. - fn reserve(&mut self, additional: usize) -> Result<()>; - /// Resizes buffer to the specified length, fills new items - /// with the specified value. - fn resize(&mut self, new_len: usize, value: u8); - /// Extends buffer with the specified slice of bytes. - fn extend(&mut self, val: &[u8]); -} - -/// A newtype for byte vectors. -/// -/// It provides convenience methods for `Pod` types. -// TODO: should this be an extension trait for `Vec` instead? -#[derive(Default, Clone, PartialEq, Eq)] -pub(crate) struct BytesMut(pub Vec); - -impl fmt::Debug for BytesMut { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - debug_list_bytes(&self.0, fmt) - } -} - -impl BytesMut { - #[inline] - pub fn new() -> Self { - BytesMut(Vec::new()) - } - - #[inline] - #[allow(dead_code)] - pub fn write(&mut self, val: &T) { - self.0.extend_from_slice(bytes_of(val)) - } - - #[inline] - pub fn write_at(&mut self, offset: usize, val: &T) -> Result<()> { - let src = bytes_of(val); - let dest = self.0.get_mut(offset..).ok_or(())?; - let dest = dest.get_mut(..src.len()).ok_or(())?; - dest.copy_from_slice(src); - Ok(()) - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0.as_slice() - } -} - -impl WritableBuffer for BytesMut { - #[inline] - fn len(&self) -> usize { - self.0.len() - } - - #[inline] - fn is_empty(&self) -> bool { - self.0.is_empty() - } - - #[inline] - fn reserve(&mut self, additional: usize) -> Result<()> { - self.0.reserve(additional); - Ok(()) - } - - #[inline] - fn resize(&mut self, new_len: usize, value: u8) { - self.0.resize(new_len, value); - } - - #[inline] - fn extend(&mut self, val: &[u8]) { - self.0.extend_from_slice(val) - } -} - -// Only for Debug impl of `Bytes/BytesMut`. +// Only for Debug impl of `Bytes`. fn debug_list_bytes(bytes: &[u8], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut list = fmt.debug_list(); list.entries(bytes.iter().take(8).copied().map(DebugByte)); @@ -605,30 +521,6 @@ mod tests { assert_eq!(data.read_string_at(3), Err(())); } - #[test] - fn bytes_mut() { - let data = BytesMut(vec![0x01, 0x23, 0x45, 0x67]); - - let mut bytes = data.clone(); - bytes.write(&u16::to_be(0x89ab)); - assert_eq!(bytes.0, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]); - - let mut bytes = data.clone(); - assert_eq!(bytes.write_at(0, &u16::to_be(0x89ab)), Ok(())); - assert_eq!(bytes.0, [0x89, 0xab, 0x45, 0x67]); - - let mut bytes = data.clone(); - assert_eq!(bytes.write_at(2, &u16::to_be(0x89ab)), Ok(())); - assert_eq!(bytes.0, [0x01, 0x23, 0x89, 0xab]); - - assert_eq!(bytes.write_at(3, &u16::to_be(0x89ab)), Err(())); - assert_eq!(bytes.write_at(4, &u16::to_be(0x89ab)), Err(())); - assert_eq!( - BytesMut::default().write_at(0, &u32::to_be(0x89ab)), - Err(()) - ); - } - #[test] fn bytes_debug() { assert_eq!(format!("{:?}", Bytes(&[])), "[]"); @@ -647,14 +539,5 @@ mod tests { ), "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ...; 9]" ); - - assert_eq!(format!("{:?}", BytesMut(vec![])), "[]"); - assert_eq!( - format!( - "{:?}", - BytesMut(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]) - ), - "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ...; 9]" - ); } } diff --git a/src/write/coff.rs b/src/write/coff.rs index b1b1e1bd..ebfdf9d6 100644 --- a/src/write/coff.rs +++ b/src/write/coff.rs @@ -3,7 +3,6 @@ use std::vec::Vec; use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32}; use crate::pe as coff; -use crate::pod::{bytes_of, WritableBuffer}; use crate::write::string::*; use crate::write::util::*; use crate::write::*; @@ -58,7 +57,7 @@ impl Object { pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec { let mut name = section.to_vec(); name.push(b'$'); - name.extend(value); + name.extend_from_slice(value); name } @@ -108,7 +107,7 @@ impl Object { let stub_size = self.architecture.address_size().unwrap().bytes(); let mut name = b".rdata$.refptr.".to_vec(); - name.extend(&self.symbols[symbol_id.0].name); + name.extend_from_slice(&self.symbols[symbol_id.0].name); let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData); let section = self.section_mut(section_id); section.set_data(vec![0; stub_size as usize], u64::from(stub_size)); @@ -122,7 +121,7 @@ impl Object { }]; let mut name = b".refptr.".to_vec(); - name.extend(&self.symbol(symbol_id).name); + name.extend_from_slice(&self.symbol(symbol_id).name); let stub_id = self.add_raw_symbol(Symbol { name, value: 0, @@ -289,7 +288,7 @@ impl Object { _ => U16::default(), }, }; - buffer.extend(bytes_of(&header)); + buffer.write(&header); // Write section headers. for (index, section) in self.sections.iter().enumerate() { @@ -417,7 +416,7 @@ impl Object { return Err(Error(format!("invalid section name offset {}", str_offset))); } } - buffer.extend(bytes_of(&coff_section)); + buffer.write(&coff_section); } // Write section data and relocations. @@ -426,7 +425,7 @@ impl Object { if len != 0 { write_align(buffer, 4); debug_assert_eq!(section_offsets[index].offset, buffer.len()); - buffer.extend(section.data.as_slice()); + buffer.write_bytes(section.data.as_slice()); } if !section.relocations.is_empty() { @@ -481,7 +480,7 @@ impl Object { ), typ: U16Bytes::new(LE, typ), }; - buffer.extend(bytes_of(&coff_relocation)); + buffer.write(&coff_relocation); } } } @@ -571,7 +570,7 @@ impl Object { let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32)); } - buffer.extend(bytes_of(&coff_symbol)); + buffer.write(&coff_symbol); // Write auxiliary symbols. match symbol.kind { @@ -579,7 +578,7 @@ impl Object { let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL; debug_assert!(aux_len >= symbol.name.len()); let old_len = buffer.len(); - buffer.extend(&symbol.name); + buffer.write_bytes(&symbol.name); buffer.resize(old_len + aux_len, 0); } SymbolKind::Section => { @@ -600,7 +599,7 @@ impl Object { // TODO: bigobj high_number: U16Bytes::default(), }; - buffer.extend(bytes_of(&aux)); + buffer.write(&aux); } _ => { debug_assert_eq!(number_of_aux_symbols, 0); @@ -610,8 +609,8 @@ impl Object { // Write strtab section. debug_assert_eq!(strtab_offset, buffer.len()); - buffer.extend(&u32::to_le_bytes(strtab_len as u32)); - buffer.extend(&strtab_data); + buffer.write_bytes(&u32::to_le_bytes(strtab_len as u32)); + buffer.write_bytes(&strtab_data); debug_assert_eq!(offset, buffer.len()); diff --git a/src/write/elf.rs b/src/write/elf.rs index b9b49c49..49cfdbc0 100644 --- a/src/write/elf.rs +++ b/src/write/elf.rs @@ -3,7 +3,6 @@ use std::vec::Vec; use crate::elf; use crate::endian::*; -use crate::pod::{bytes_of, BytesMut, WritableBuffer}; use crate::write::string::*; use crate::write::util::*; use crate::write::*; @@ -66,7 +65,7 @@ impl Object { pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec { let mut name = section.to_vec(); name.push(b'.'); - name.extend(value); + name.extend_from_slice(value); name } @@ -417,23 +416,26 @@ impl Object { // Write section data. for (index, comdat) in self.comdats.iter().enumerate() { - let mut data = BytesMut::new(); - data.write(&U32::new(endian, elf::GRP_COMDAT)); + let mut data = Vec::new(); + data.write_pod(&U32::new(self.endian, elf::GRP_COMDAT)); for section in &comdat.sections { - data.write(&U32::new(endian, section_offsets[section.0].index as u32)); + data.write_pod(&U32::new( + self.endian, + section_offsets[section.0].index as u32, + )); } write_align(buffer, 4); debug_assert_eq!(comdat_offsets[index].offset, buffer.len()); debug_assert_eq!(comdat_offsets[index].len, data.len()); - buffer.extend(data.as_slice()); + buffer.write_slice(&data); } for (index, section) in self.sections.iter().enumerate() { let len = section.data.len(); if len != 0 { write_align(buffer, section.align as usize); debug_assert_eq!(section_offsets[index].offset, buffer.len()); - buffer.extend(section.data.as_slice()); + buffer.write_slice(§ion.data); } } @@ -451,9 +453,9 @@ impl Object { st_size: 0, }, ); - let mut symtab_shndx = BytesMut::new(); + let mut symtab_shndx = Vec::new(); if need_symtab_shndx { - symtab_shndx.write(&U32::new(endian, 0)); + symtab_shndx.write_pod(&U32::new(endian, 0)); } let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> { let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags { @@ -547,7 +549,7 @@ impl Object { }, ); if need_symtab_shndx { - symtab_shndx.write(&U32::new(endian, xindex)); + symtab_shndx.write_pod(&U32::new(endian, xindex)); } Ok(()) }; @@ -564,12 +566,12 @@ impl Object { if need_symtab_shndx { debug_assert_eq!(symtab_shndx_offset, buffer.len()); debug_assert_eq!(symtab_shndx_len, symtab_shndx.len()); - buffer.extend(symtab_shndx.as_slice()); + buffer.write_slice(symtab_shndx.as_slice()); } // Write strtab section. debug_assert_eq!(strtab_offset, buffer.len()); - buffer.extend(&strtab_data); + buffer.write_slice(&strtab_data); // Write relocations. for (index, section) in self.sections.iter().enumerate() { @@ -831,7 +833,7 @@ impl Object { // Write shstrtab section. debug_assert_eq!(shstrtab_offset, buffer.len()); - buffer.extend(&shstrtab_data); + buffer.write_slice(&shstrtab_data); // Write section headers. write_align(buffer, pointer_align); @@ -1152,7 +1154,7 @@ impl Elf for Elf32 { e_shnum: U16::new(endian, file.e_shnum), e_shstrndx: U16::new(endian, file.e_shstrndx), }; - buffer.extend(bytes_of(&file)); + buffer.write(&file); } fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { @@ -1169,7 +1171,7 @@ impl Elf for Elf32 { sh_addralign: U32::new(endian, section.sh_addralign as u32), sh_entsize: U32::new(endian, section.sh_entsize as u32), }; - buffer.extend(bytes_of(§ion)); + buffer.write(§ion); } fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) { @@ -1182,7 +1184,7 @@ impl Elf for Elf32 { st_value: U32::new(endian, symbol.st_value as u32), st_size: U32::new(endian, symbol.st_size as u32), }; - buffer.extend(bytes_of(&symbol)); + buffer.write(&symbol); } fn write_rel( @@ -1199,13 +1201,13 @@ impl Elf for Elf32 { r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), r_addend: I32::new(endian, rel.r_addend as i32), }; - buffer.extend(bytes_of(&rel)); + buffer.write(&rel); } else { let rel = elf::Rel32 { r_offset: U32::new(endian, rel.r_offset as u32), r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), }; - buffer.extend(bytes_of(&rel)); + buffer.write(&rel); } } } @@ -1253,7 +1255,7 @@ impl Elf for Elf64 { e_shnum: U16::new(endian, file.e_shnum), e_shstrndx: U16::new(endian, file.e_shstrndx), }; - buffer.extend(bytes_of(&file)) + buffer.write(&file) } fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { @@ -1270,7 +1272,7 @@ impl Elf for Elf64 { sh_addralign: U64::new(endian, section.sh_addralign), sh_entsize: U64::new(endian, section.sh_entsize), }; - buffer.extend(bytes_of(§ion)); + buffer.write(§ion); } fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) { @@ -1283,7 +1285,7 @@ impl Elf for Elf64 { st_value: U64::new(endian, symbol.st_value), st_size: U64::new(endian, symbol.st_size), }; - buffer.extend(bytes_of(&symbol)); + buffer.write(&symbol); } fn write_rel( @@ -1300,13 +1302,13 @@ impl Elf for Elf64 { r_info: elf::Rela64::r_info2(endian, is_mips64el, rel.r_sym, rel.r_type), r_addend: I64::new(endian, rel.r_addend), }; - buffer.extend(bytes_of(&rel)); + buffer.write(&rel); } else { let rel = elf::Rel64 { r_offset: U64::new(endian, rel.r_offset), r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type), }; - buffer.extend(bytes_of(&rel)); + buffer.write(&rel); } } } diff --git a/src/write/macho.rs b/src/write/macho.rs index d102da3d..a8d8ea49 100644 --- a/src/write/macho.rs +++ b/src/write/macho.rs @@ -2,7 +2,6 @@ use std::mem; use crate::endian::*; use crate::macho; -use crate::pod::{bytes_of, WritableBuffer}; use crate::write::string::*; use crate::write::util::*; use crate::write::*; @@ -116,7 +115,7 @@ impl Object { // Create the initializer symbol. let mut name = symbol.name.clone(); - name.extend(b"$tlv$init"); + name.extend_from_slice(b"$tlv$init"); let init_symbol_id = self.add_raw_symbol(Symbol { name, value: 0, @@ -443,7 +442,7 @@ impl Object { stroff: U32::new(endian, strtab_offset as u32), strsize: U32::new(endian, strtab_data.len() as u32), }; - buffer.extend(bytes_of(&symtab_command)); + buffer.write(&symtab_command); // Write section data. for (index, section) in self.sections.iter().enumerate() { @@ -451,7 +450,7 @@ impl Object { if len != 0 { write_align(buffer, section.align as usize); debug_assert_eq!(section_offsets[index].offset, buffer.len()); - buffer.extend(section.data.as_slice()); + buffer.write_bytes(section.data.as_slice()); } } debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len()); @@ -524,7 +523,7 @@ impl Object { // Write strtab. debug_assert_eq!(strtab_offset, buffer.len()); - buffer.extend(&strtab_data); + buffer.write_bytes(&strtab_data); // Write relocations. for (index, section) in self.sections.iter().enumerate() { @@ -600,7 +599,7 @@ impl Object { r_extern, r_type, }; - buffer.extend(bytes_of(&reloc_info.relocation(endian))); + buffer.write(&reloc_info.relocation(endian)); } } } @@ -701,7 +700,7 @@ impl MachO for MachO32 { sizeofcmds: U32::new(endian, header.sizeofcmds), flags: U32::new(endian, header.flags), }; - buffer.extend(bytes_of(&header)); + buffer.write(&header); } fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { @@ -719,7 +718,7 @@ impl MachO for MachO32 { nsects: U32::new(endian, segment.nsects), flags: U32::new(endian, segment.flags), }; - buffer.extend(bytes_of(&segment)); + buffer.write(&segment); } fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { @@ -737,7 +736,7 @@ impl MachO for MachO32 { reserved1: U32::default(), reserved2: U32::default(), }; - buffer.extend(bytes_of(§ion)); + buffer.write(§ion); } fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { @@ -749,7 +748,7 @@ impl MachO for MachO32 { n_desc: U16::new(endian, nlist.n_desc), n_value: U32::new(endian, nlist.n_value as u32), }; - buffer.extend(bytes_of(&nlist)); + buffer.write(&nlist); } } @@ -791,7 +790,7 @@ impl MachO for MachO64 { flags: U32::new(endian, header.flags), reserved: U32::default(), }; - buffer.extend(bytes_of(&header)); + buffer.write(&header); } fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { @@ -809,7 +808,7 @@ impl MachO for MachO64 { nsects: U32::new(endian, segment.nsects), flags: U32::new(endian, segment.flags), }; - buffer.extend(bytes_of(&segment)); + buffer.write(&segment); } fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { @@ -828,7 +827,7 @@ impl MachO for MachO64 { reserved2: U32::default(), reserved3: U32::default(), }; - buffer.extend(bytes_of(§ion)); + buffer.write(§ion); } fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { @@ -840,6 +839,6 @@ impl MachO for MachO64 { n_desc: U16::new(endian, nlist.n_desc), n_value: U64Bytes::new(endian, nlist.n_value), }; - buffer.extend(bytes_of(&nlist)); + buffer.write(&nlist); } } diff --git a/src/write/mod.rs b/src/write/mod.rs index 4d6cb2bb..747e2a02 100644 --- a/src/write/mod.rs +++ b/src/write/mod.rs @@ -6,7 +6,6 @@ use std::vec::Vec; use std::{error, fmt, result, str}; use crate::endian::{Endianness, U32, U64}; -use crate::pod::{BytesMut, WritableBuffer}; use crate::{ Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, RelocationKind, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, @@ -20,6 +19,7 @@ mod elf; mod macho; mod string; mod util; +pub use util::*; /// The error type used within the write module. #[derive(Debug, Clone, PartialEq, Eq)] @@ -162,7 +162,7 @@ impl Object { kind, size: 0, align: 1, - data: BytesMut::new(), + data: Vec::new(), relocations: Vec::new(), symbol: None, flags: SectionFlags::None, @@ -520,9 +520,9 @@ impl Object { /// Write the object to a `Vec`. pub fn write(&self) -> Result> { - let mut buffer = BytesMut::new(); + let mut buffer = Vec::new(); self.emit(&mut buffer)?; - Ok(buffer.0) + Ok(buffer) } /// Write the object to a `WritableBuffer`. @@ -616,7 +616,7 @@ pub struct Section { kind: SectionKind, size: u64, align: u64, - data: BytesMut, + data: Vec, relocations: Vec, symbol: Option, /// Section flags that are specific to each file format. @@ -650,7 +650,7 @@ impl Section { debug_assert_eq!(align & (align - 1), 0); debug_assert!(self.data.is_empty()); self.size = data.len() as u64; - self.data = BytesMut(data); + self.data = data; self.align = align; } @@ -669,7 +669,7 @@ impl Section { offset += align - (offset & (align - 1)); self.data.resize(offset, 0); } - self.data.extend(data); + self.data.extend_from_slice(data); self.size = self.data.len() as u64; offset as u64 } diff --git a/src/write/util.rs b/src/write/util.rs index c108f474..bb6b8597 100644 --- a/src/write/util.rs +++ b/src/write/util.rs @@ -1,4 +1,92 @@ -use crate::pod::WritableBuffer; +use std::vec::Vec; + +use crate::pod::{bytes_of, bytes_of_slice, Pod}; + +/// Trait for writable buffer. +#[allow(clippy::len_without_is_empty)] +pub trait WritableBuffer { + /// Returns position/offset for data to be written at. + fn len(&self) -> usize; + + /// Reserves specified number of bytes in the buffer. + fn reserve(&mut self, additional: usize) -> Result<(), ()>; + + /// Writes the specified value at the end of the buffer + /// until the buffer has the specified length. + fn resize(&mut self, new_len: usize, value: u8); + + /// Writes the specified slice of bytes at the end of the buffer. + fn write_bytes(&mut self, val: &[u8]); + + /// Writes the specified `Pod` type at the end of the buffer. + fn write_pod(&mut self, val: &T) + where + Self: Sized, + { + self.write_bytes(bytes_of(val)) + } + + /// Writes the specified `Pod` slice at the end of the buffer. + fn write_pod_slice(&mut self, val: &[T]) + where + Self: Sized, + { + self.write_bytes(bytes_of_slice(val)) + } +} + +impl<'a> dyn WritableBuffer + 'a { + /// Writes the specified `Pod` type at the end of the buffer. + pub fn write(&mut self, val: &T) { + self.write_bytes(bytes_of(val)) + } + + /// Writes the specified `Pod` slice at the end of the buffer. + pub fn write_slice(&mut self, val: &[T]) { + self.write_bytes(bytes_of_slice(val)) + } +} + +impl WritableBuffer for Vec { + #[inline] + fn len(&self) -> usize { + self.len() + } + + #[inline] + fn reserve(&mut self, additional: usize) -> Result<(), ()> { + self.reserve(additional); + Ok(()) + } + + #[inline] + fn resize(&mut self, new_len: usize, value: u8) { + self.resize(new_len, value); + } + + #[inline] + fn write_bytes(&mut self, val: &[u8]) { + self.extend_from_slice(val) + } +} + +/// A trait for mutable byte slices. +/// +/// It provides convenience methods for `Pod` types. +pub(crate) trait BytesMut { + fn write_at(self, offset: usize, val: &T) -> Result<(), ()>; +} + +impl<'a> BytesMut for &'a mut [u8] { + #[inline] + fn write_at(self, offset: usize, val: &T) -> Result<(), ()> { + let src = bytes_of(val); + let dest = self.get_mut(offset..).ok_or(())?; + let dest = dest.get_mut(..src.len()).ok_or(())?; + dest.copy_from_slice(src); + Ok(()) + } +} pub(crate) fn align(offset: usize, size: usize) -> usize { (offset + (size - 1)) & !(size - 1) @@ -13,3 +101,29 @@ pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) { let new_len = align(buffer.len(), size); buffer.resize(new_len, 0); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bytes_mut() { + let data = vec![0x01, 0x23, 0x45, 0x67]; + + let mut bytes = data.clone(); + bytes.extend_from_slice(bytes_of(&u16::to_be(0x89ab))); + assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]); + + let mut bytes = data.clone(); + assert_eq!(bytes.write_at(0, &u16::to_be(0x89ab)), Ok(())); + assert_eq!(bytes, [0x89, 0xab, 0x45, 0x67]); + + let mut bytes = data.clone(); + assert_eq!(bytes.write_at(2, &u16::to_be(0x89ab)), Ok(())); + assert_eq!(bytes, [0x01, 0x23, 0x89, 0xab]); + + assert_eq!(bytes.write_at(3, &u16::to_be(0x89ab)), Err(())); + assert_eq!(bytes.write_at(4, &u16::to_be(0x89ab)), Err(())); + assert_eq!(vec![].write_at(0, &u32::to_be(0x89ab)), Err(())); + } +}