1use crate::macros::passthrough_trait_fn;
10#[cfg(feature = "vm-memory")]
11use crate::misc_helpers::ImagoAsRef;
12use std::alloc::{self, GlobalAlloc};
13use std::fmt::{self, Debug, Formatter};
14use std::io::{IoSlice, IoSliceMut};
15use std::marker::PhantomData;
16#[cfg(unix)]
17use std::mem;
18use std::mem::{size_of, size_of_val};
19use std::ops::Range;
20use std::{cmp, io, ptr, slice};
21
22pub struct IoBuffer {
24 pointer: *mut u8,
26
27 size: usize,
29
30 layout: Option<alloc::Layout>,
32}
33
34pub struct IoBufferRef<'a> {
36 pointer: *const u8,
38
39 size: usize,
41
42 _lifetime: PhantomData<&'a [u8]>,
44}
45
46pub struct IoBufferMut<'a> {
48 pointer: *mut u8,
50
51 size: usize,
53
54 _lifetime: PhantomData<&'a mut [u8]>,
56}
57
58unsafe impl Send for IoBuffer {}
60unsafe impl Sync for IoBuffer {}
61unsafe impl Send for IoBufferRef<'_> {}
62unsafe impl Sync for IoBufferRef<'_> {}
63unsafe impl Send for IoBufferMut<'_> {}
64unsafe impl Sync for IoBufferMut<'_> {}
65
66impl IoBuffer {
67 pub fn new(size: usize, alignment: usize) -> io::Result<Self> {
72 let layout = alloc::Layout::from_size_align(size, alignment).map_err(io::Error::other)?;
73 Self::new_with_layout(layout)
74 }
75
76 pub fn new_with_layout(layout: alloc::Layout) -> io::Result<Self> {
78 if layout.size() == 0 {
79 return Ok(IoBuffer {
80 pointer: ptr::null_mut(),
81 size: 0,
82 layout: None,
83 });
84 }
85
86 let pointer = unsafe { alloc::System.alloc(layout) };
89
90 if pointer.is_null() {
91 return Err(io::Error::new(
92 io::ErrorKind::OutOfMemory,
93 format!(
94 "Failed to allocate memory (size={}, alignment={})",
95 layout.size(),
96 layout.align(),
97 ),
98 ));
99 }
100
101 Ok(IoBuffer {
102 pointer,
103 size: layout.size(),
104 layout: Some(layout),
105 })
106 }
107
108 pub fn len(&self) -> usize {
110 self.size
111 }
112
113 pub fn is_empty(&self) -> bool {
115 self.size == 0
116 }
117
118 pub fn as_ref(&self) -> IoBufferRef<'_> {
120 IoBufferRef {
121 pointer: self.pointer as *const u8,
122 size: self.size,
123 _lifetime: PhantomData,
124 }
125 }
126
127 pub fn as_ref_range(&self, range: Range<usize>) -> IoBufferRef<'_> {
129 IoBufferRef::from_slice(&self.as_ref().into_slice()[range])
130 }
131
132 pub fn as_mut(&mut self) -> IoBufferMut<'_> {
134 IoBufferMut {
135 pointer: self.pointer,
136 size: self.size,
137 _lifetime: PhantomData,
138 }
139 }
140
141 pub fn as_mut_range(&mut self, range: Range<usize>) -> IoBufferMut<'_> {
143 (&mut self.as_mut().into_slice()[range]).into()
144 }
145}
146
147impl Drop for IoBuffer {
148 fn drop(&mut self) {
150 if let Some(layout) = self.layout {
151 unsafe {
153 alloc::System.dealloc(self.pointer, layout);
154 }
155 }
156 }
157}
158
159#[allow(dead_code)]
161pub(crate) trait IoBufferRefTrait<'a>: Sized {
162 type SliceType<T: Copy + Sized + 'a>;
164
165 type PointerType<T: Copy + Sized + 'a>;
167
168 fn from_slice(slice: Self::SliceType<u8>) -> Self;
170
171 fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>;
173
174 fn len(&self) -> usize;
176
177 fn is_empty(&self) -> bool {
179 self.len() == 0
180 }
181
182 fn as_ptr(&self) -> Self::PointerType<u8>;
184
185 fn into_slice(self) -> Self::SliceType<u8> {
191 unsafe { self.into_typed_slice::<u8>() }
193 }
194
195 unsafe fn into_typed_slice<T: Copy + Sized>(self) -> Self::SliceType<T>;
201
202 fn split_at(self, mid: usize) -> (Self, Self);
208
209 fn into_ref(self) -> IoBufferRef<'a>;
211}
212
213impl<'a> IoBufferRef<'a> {
214 pub fn from_slice(slice: &'a [u8]) -> Self {
216 IoBufferRef {
217 pointer: slice.as_ptr(),
218 size: size_of_val(slice),
219 _lifetime: PhantomData,
220 }
221 }
222
223 pub fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer> {
225 let mut new_buf = IoBuffer::new(self.len(), alignment)?;
226 new_buf
227 .as_mut()
228 .into_slice()
229 .copy_from_slice(self.into_slice());
230 Ok(new_buf)
231 }
232
233 pub fn len(&self) -> usize {
235 self.size
236 }
237
238 pub fn is_empty(&self) -> bool {
240 self.len() == 0
241 }
242
243 pub fn as_ptr(&self) -> *const u8 {
245 self.pointer
246 }
247
248 pub fn into_slice(self) -> &'a [u8] {
254 unsafe { self.into_typed_slice::<u8>() }
256 }
257
258 pub unsafe fn into_typed_slice<T: Copy + Sized>(self) -> &'a [T] {
264 if self.is_empty() {
265 return &[];
266 }
267
268 unsafe { slice::from_raw_parts(self.as_ptr() as *const T, self.len() / size_of::<T>()) }
271 }
272
273 pub fn split_at(self, mid: usize) -> (IoBufferRef<'a>, IoBufferRef<'a>) {
279 let head_len = cmp::min(mid, self.size);
280
281 (
282 IoBufferRef {
283 pointer: self.pointer,
284 size: head_len,
285 _lifetime: PhantomData,
286 },
287 IoBufferRef {
288 pointer: unsafe { self.pointer.add(head_len) },
290 size: self.size - head_len,
291 _lifetime: PhantomData,
292 },
293 )
294 }
295
296 pub fn into_ref(self) -> IoBufferRef<'a> {
298 self
299 }
300}
301
302impl<'a> IoBufferRefTrait<'a> for IoBufferRef<'a> {
303 type SliceType<T: Copy + Sized + 'a> = &'a [T];
304 type PointerType<T: Copy + Sized + 'a> = *const T;
305
306 passthrough_trait_fn! { fn from_slice(slice: Self::SliceType<u8>) -> Self; }
307 passthrough_trait_fn! { fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>; }
308 passthrough_trait_fn! { fn len(&self) -> usize; }
309 passthrough_trait_fn! { fn as_ptr(&self) -> Self::PointerType<u8>; }
310 passthrough_trait_fn! { fn split_at(self, mid: usize) -> (Self, Self); }
311 passthrough_trait_fn! { fn into_ref(self) -> IoBufferRef<'a>; }
312
313 unsafe fn into_typed_slice<T: Copy + Sized>(self) -> Self::SliceType<T> {
314 unsafe { Self::into_typed_slice(self) }
316 }
317}
318
319impl<'a> From<IoSlice<'a>> for IoBufferRef<'a> {
320 fn from(slice: IoSlice<'a>) -> Self {
321 IoBufferRef {
322 pointer: slice.as_ptr(),
323 size: slice.len(),
324 _lifetime: PhantomData,
325 }
326 }
327}
328
329impl<'a> From<IoBufferRef<'a>> for IoSlice<'a> {
330 fn from(buf: IoBufferRef<'a>) -> Self {
331 IoSlice::new(buf.into_slice())
332 }
333}
334
335impl<'a> IoBufferMut<'a> {
336 pub fn from_slice(slice: &'a mut [u8]) -> Self {
338 IoBufferMut {
339 pointer: slice.as_mut_ptr(),
340 size: size_of_val(slice),
341 _lifetime: PhantomData,
342 }
343 }
344
345 pub fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer> {
347 let mut new_buf = IoBuffer::new(self.len(), alignment)?;
348 new_buf
349 .as_mut()
350 .into_slice()
351 .copy_from_slice(self.into_slice());
352 Ok(new_buf)
353 }
354
355 pub fn len(&self) -> usize {
357 self.size
358 }
359
360 pub fn is_empty(&self) -> bool {
362 self.len() == 0
363 }
364
365 pub fn as_ptr(&self) -> *mut u8 {
367 self.pointer
368 }
369
370 pub fn into_slice(self) -> &'a mut [u8] {
376 unsafe { self.into_typed_slice::<u8>() }
378 }
379
380 pub unsafe fn into_typed_slice<T: Copy + Sized>(self) -> &'a mut [T] {
386 if self.is_empty() {
387 return &mut [];
388 }
389
390 unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut T, self.len() / size_of::<T>()) }
393 }
394
395 pub fn split_at(self, mid: usize) -> (IoBufferMut<'a>, IoBufferMut<'a>) {
401 let head_len = cmp::min(mid, self.size);
402
403 (
404 IoBufferMut {
405 pointer: self.pointer,
406 size: head_len,
407 _lifetime: PhantomData,
408 },
409 IoBufferMut {
410 pointer: unsafe { self.pointer.add(head_len) },
412 size: self.size - head_len,
413 _lifetime: PhantomData,
414 },
415 )
416 }
417
418 pub fn into_ref(self) -> IoBufferRef<'a> {
420 IoBufferRef {
421 pointer: self.pointer,
422 size: self.size,
423 _lifetime: PhantomData,
424 }
425 }
426}
427
428impl<'a> IoBufferRefTrait<'a> for IoBufferMut<'a> {
429 type SliceType<T: Copy + Sized + 'a> = &'a mut [T];
430 type PointerType<T: Copy + Sized + 'a> = *mut T;
431
432 passthrough_trait_fn! { fn from_slice(slice: Self::SliceType<u8>) -> Self; }
433 passthrough_trait_fn! { fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>; }
434 passthrough_trait_fn! { fn len(&self) -> usize; }
435 passthrough_trait_fn! { fn as_ptr(&self) -> Self::PointerType<u8>; }
436 passthrough_trait_fn! { fn split_at(self, mid: usize) -> (Self, Self); }
437 passthrough_trait_fn! { fn into_ref(self) -> IoBufferRef<'a>; }
438
439 unsafe fn into_typed_slice<T: Copy + Sized>(self) -> Self::SliceType<T> {
440 unsafe { Self::into_typed_slice(self) }
442 }
443}
444
445impl<'a, T: Sized> From<&'a mut [T]> for IoBufferMut<'a> {
446 fn from(slice: &'a mut [T]) -> Self {
447 IoBufferMut {
448 pointer: slice.as_mut_ptr() as *mut u8,
449 size: size_of_val(slice),
450 _lifetime: PhantomData,
451 }
452 }
453}
454
455impl<'a> From<IoSliceMut<'a>> for IoBufferMut<'a> {
456 fn from(mut slice: IoSliceMut<'a>) -> Self {
457 IoBufferMut {
458 pointer: slice.as_mut_ptr(),
459 size: slice.len(),
460 _lifetime: PhantomData,
461 }
462 }
463}
464
465impl<'a> From<IoBufferMut<'a>> for IoSliceMut<'a> {
466 fn from(buf: IoBufferMut<'a>) -> Self {
467 IoSliceMut::new(buf.into_slice())
468 }
469}
470
471#[allow(dead_code)]
473pub(crate) trait IoVectorTrait: Sized {
474 type SliceType;
476
477 type BufferType;
479
480 fn new() -> Self;
482
483 fn with_capacity(cap: usize) -> Self;
487
488 fn push(&mut self, slice: Self::SliceType);
490
491 fn push_ioslice(&mut self, ioslice: Self::BufferType);
493
494 fn insert(&mut self, index: usize, slice: Self::SliceType);
496
497 fn len(&self) -> u64;
499
500 fn buffer_count(&self) -> usize;
502
503 fn is_empty(&self) -> bool {
507 debug_assert!((self.len() == 0) == (self.buffer_count() == 0));
508 self.len() == 0
509 }
510
511 fn append(&mut self, other: Self);
513
514 fn split_at(self, mid: u64) -> (Self, Self);
519
520 fn split_tail_at(self, mid: u64) -> Self;
525
526 fn copy_into_slice(&self, slice: &mut [u8]);
530
531 fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>;
533
534 #[cfg(unix)]
540 unsafe fn as_iovec<'a>(&'a self) -> &'a [libc::iovec]
541 where
542 Self: 'a;
543
544 fn is_aligned(&self, mem_alignment: usize, req_alignment: usize) -> bool;
549
550 fn into_inner(self) -> Vec<Self::BufferType>;
552}
553
554macro_rules! impl_io_vector {
556 ($type:tt, $inner_type:tt, $buffer_type:tt, $slice_type:ty, $slice_type_lifetime_b:ty) => {
557 pub struct $type<'a> {
559 vector: Vec<$inner_type<'a>>,
561
562 total_size: u64,
564 }
565
566 impl<'a> $type<'a> {
567 pub fn new() -> Self {
569 Self::default()
570 }
571
572 pub fn with_capacity(cap: usize) -> Self {
576 $type {
577 vector: Vec::with_capacity(cap),
578 total_size: 0,
579 }
580 }
581
582 pub fn push(&mut self, slice: $slice_type) {
584 debug_assert!(!slice.is_empty());
585 self.total_size += slice.len() as u64;
586 self.vector.push($inner_type::new(slice));
587 }
588
589 pub fn push_ioslice(&mut self, ioslice: $inner_type<'a>) {
591 debug_assert!(!ioslice.is_empty());
592 self.total_size += ioslice.len() as u64;
593 self.vector.push(ioslice);
594 }
595
596 pub fn insert(&mut self, index: usize, slice: $slice_type) {
598 debug_assert!(!slice.is_empty());
599 self.total_size += slice.len() as u64;
600 self.vector.insert(index, $inner_type::new(slice));
601 }
602
603 pub fn len(&self) -> u64 {
605 self.total_size
606 }
607
608 pub fn buffer_count(&self) -> usize {
610 self.vector.len()
611 }
612
613 pub fn is_empty(&self) -> bool {
617 debug_assert!((self.len() == 0) == (self.buffer_count() == 0));
618 self.len() == 0
619 }
620
621 pub fn append(&mut self, mut other: Self) {
623 self.total_size += other.total_size;
624 self.vector.append(&mut other.vector);
625 }
626
627 pub fn split_at(self, mid: u64) -> (Self, Self) {
632 let (head, tail) = self.do_split_at(mid, true);
633 (head.unwrap(), tail)
634 }
635
636 pub fn split_tail_at(self, mid: u64) -> Self {
641 self.do_split_at(mid, false).1
642 }
643
644 pub fn copy_into_slice(&self, slice: &mut [u8]) {
648 if slice.len() as u64 != self.total_size {
649 panic!("IoVectorTrait::copy_into_slice() called on a slice of different length from the vector");
650 }
651
652 assert!(self.total_size <= usize::MAX as u64);
653
654 let mut offset = 0usize;
655 for elem in self.vector.iter() {
656 let next_offset = offset + elem.len();
657 slice[offset..next_offset].copy_from_slice(&elem[..]);
658 offset = next_offset;
659 }
660 }
661
662 pub fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer> {
664 let size = self.total_size.try_into().map_err(|_| {
665 io::Error::other(format!("Buffer is too big ({})", self.total_size))
666 })?;
667 let mut new_buf = IoBuffer::new(size, alignment)?;
668 self.copy_into_slice(new_buf.as_mut().into_slice());
669 Ok(new_buf)
670 }
671
672 #[cfg(unix)]
678 pub unsafe fn as_iovec<'b>(&'b self) -> &'b [libc::iovec] where Self: 'b {
679 unsafe {
682 mem::transmute::<&'b [$inner_type<'b>], &'b [libc::iovec]>(&self.vector[..])
683 }
684 }
685
686 pub fn is_aligned(&self, mem_alignment: usize, req_alignment: usize) -> bool {
692 if mem_alignment == 1 && req_alignment == 1 {
694 return true;
695 }
696
697 debug_assert!(mem_alignment.is_power_of_two() && req_alignment.is_power_of_two());
698 let base_align_mask = mem_alignment - 1;
699 let len_align_mask = base_align_mask | (req_alignment - 1);
700
701 self.vector.iter().all(|buf| {
702 buf.as_ptr() as usize & base_align_mask == 0 &&
703 buf.len() & len_align_mask == 0
704 })
705 }
706
707 pub fn into_inner(self) -> Vec<$inner_type<'a>> {
709 self.vector
710 }
711
712 pub fn with_pushed<'b>(self, slice: $slice_type_lifetime_b) -> $type<'b>
717 where
718 'a: 'b,
719 {
720 let mut vec: $type<'b> = self;
721 vec.push(slice);
722 vec
723 }
724
725 pub fn with_inserted<'b>(self, index: usize, slice: $slice_type_lifetime_b) -> $type<'b>
730 where
731 'a: 'b,
732 {
733 let mut vec: $type<'b> = self;
734 vec.insert(index, slice);
735 vec
736 }
737
738 fn do_split_at(mut self, mid: u64, keep_head: bool) -> (Option<$type<'a>>, $type<'a>) {
743 if mid >= self.total_size {
744 return (
746 keep_head.then_some(self),
747 $type {
748 vector: Vec::new(),
749 total_size: 0,
750 },
751 );
752 }
753
754 let mut i = 0; let mut offset = 0u64; let (vec_head, vec_tail) = loop {
757 if offset == mid {
758 if keep_head {
760 let mut vec_head = self.vector;
761 let vec_tail = vec_head.split_off(i);
762 break (Some(vec_head), vec_tail);
763 } else {
764 break (None, self.vector.split_off(i));
765 }
766 }
767
768 let post_elm_offset = offset + self.vector[i].len() as u64;
769
770 if post_elm_offset > mid {
771 let mut vec_head = self.vector;
774 let mut tail_iter = vec_head.drain(i..);
775
776 let mid_elm = tail_iter.next().unwrap();
778 let mid_elm: $buffer_type<'a> = mid_elm.into();
779
780 let mid_elm_head_len: usize = (mid - offset).try_into().unwrap();
782 let (mid_head, mid_tail) = mid_elm.split_at(mid_elm_head_len);
783
784 let mut vec_tail: Vec<$inner_type<'a>> = vec![mid_tail.into()];
785 vec_tail.extend(tail_iter);
786
787 if keep_head {
788 vec_head.push(mid_head.into());
789 break (Some(vec_head), vec_tail);
790 } else {
791 break (None, vec_tail);
792 }
793 }
794
795 offset = post_elm_offset;
796
797 i += 1;
798 assert!(i < self.vector.len());
801 };
802
803 let head = keep_head.then(|| $type {
804 vector: vec_head.unwrap(),
805 total_size: mid,
806 });
807 let tail = $type {
808 vector: vec_tail,
809 total_size: self.total_size - mid,
810 };
811
812 (head, tail)
813 }
814 }
815
816 impl<'a> IoVectorTrait for $type<'a> {
817 type SliceType = $slice_type;
818 type BufferType = $inner_type<'a>;
819
820 passthrough_trait_fn! { fn new() -> Self; }
821 passthrough_trait_fn! { fn with_capacity(cap: usize) -> Self; }
822 passthrough_trait_fn! { fn push(&mut self, slice: Self::SliceType); }
823 passthrough_trait_fn! { fn push_ioslice(&mut self, ioslice: Self::BufferType); }
824 passthrough_trait_fn! { fn insert(&mut self, index: usize, slice: Self::SliceType); }
825 passthrough_trait_fn! { fn len(&self) -> u64; }
826 passthrough_trait_fn! { fn buffer_count(&self) -> usize; }
827 passthrough_trait_fn! { fn append(&mut self, other: Self); }
828 passthrough_trait_fn! { fn split_at(self, mid: u64) -> (Self, Self); }
829 passthrough_trait_fn! { fn split_tail_at(self, mid: u64) -> Self; }
830 passthrough_trait_fn! { fn copy_into_slice(&self, slice: &mut [u8]); }
831 passthrough_trait_fn! { fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>; }
832 passthrough_trait_fn! { fn is_aligned(&self, mem_alignment: usize, req_alignment: usize) -> bool; }
833 passthrough_trait_fn! { fn into_inner(self) -> Vec<Self::BufferType>; }
834
835 #[cfg(unix)]
836 unsafe fn as_iovec<'b>(&'b self) -> &'b [libc::iovec]
837 where
838 Self: 'b
839 {
840 unsafe { Self::as_iovec(self) }
842 }
843 }
844
845 impl<'a> From<Vec<$inner_type<'a>>> for $type<'a> {
846 fn from(vector: Vec<$inner_type<'a>>) -> Self {
847 let total_size = vector
848 .iter()
849 .map(|e| e.len())
850 .fold(0u64, |sum, e| sum + e as u64);
851
852 $type { vector, total_size }
853 }
854 }
855
856 impl<'a> From<$buffer_type<'a>> for $type<'a> {
857 fn from(buffer: $buffer_type<'a>) -> Self {
858 let total_size = buffer.len() as u64;
859 if total_size > 0 {
860 $type {
861 vector: vec![buffer.into()],
862 total_size,
863 }
864 } else {
865 $type {
866 vector: Vec::new(),
867 total_size: 0,
868 }
869 }
870 }
871 }
872
873 impl<'a> From<$slice_type> for $type<'a> {
874 fn from(slice: $slice_type) -> Self {
875 let total_size = slice.len() as u64;
876 if total_size > 0 {
877 $type {
878 vector: vec![$inner_type::new(slice)],
879 total_size,
880 }
881 } else {
882 $type {
883 vector: Vec::new(),
884 total_size: 0,
885 }
886 }
887 }
888 }
889
890 impl<'a> Default for $type<'a> {
891 fn default() -> Self {
892 $type {
893 vector: Vec::new(),
894 total_size: 0,
895 }
896 }
897 }
898
899 impl Debug for $type<'_> {
900 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
901 f.debug_struct(std::stringify!($type))
902 .field("vector.len()", &self.vector.len())
903 .field("total_size", &self.total_size)
904 .finish()
905 }
906 }
907 };
908}
909
910impl_io_vector!(IoVector, IoSlice, IoBufferRef, &'a [u8], &'b [u8]);
911impl_io_vector!(
912 IoVectorMut,
913 IoSliceMut,
914 IoBufferMut,
915 &'a mut [u8],
916 &'b mut [u8]
917);
918
919#[cfg(feature = "vm-memory")]
920impl<'a> IoVector<'a> {
921 pub fn from_volatile_slice<
926 B: vm_memory::bitmap::BitmapSlice,
927 I: IntoIterator<
928 Item: ImagoAsRef<'a, vm_memory::VolatileSlice<'a, B>>,
929 IntoIter: ExactSizeIterator,
930 >,
931 >(
932 slices: I,
933 ) -> (
934 Self,
935 VolatileSliceGuard<'a, vm_memory::volatile_memory::PtrGuard, B>,
936 ) {
937 let ptr_guards = slices
938 .into_iter()
939 .map(|slice| slice.as_ref().ptr_guard())
940 .collect::<Vec<_>>();
941 let buffers = ptr_guards
942 .iter()
943 .map(|pg| {
944 let slice = if pg.len() == 0 {
945 &[]
946 } else {
947 unsafe { std::slice::from_raw_parts(pg.as_ptr(), pg.len()) }
950 };
951 IoSlice::new(slice)
952 })
953 .collect::<Vec<_>>();
954
955 let vector = IoVector::from(buffers);
956 let guard = VolatileSliceGuard {
957 _ptr_guards: ptr_guards,
958 dirty_on_drop: None,
960 };
961
962 (vector, guard)
963 }
964}
965
966impl IoVectorMut<'_> {
967 pub fn fill(&mut self, value: u8) {
969 for slice in self.vector.iter_mut() {
970 slice.fill(value);
971 }
972 }
973
974 pub fn copy_from_slice(&mut self, slice: &[u8]) {
978 if slice.len() as u64 != self.total_size {
979 panic!("IoVectorMut::copy_from_slice() called on a slice of different length from the vector");
980 }
981
982 assert!(self.total_size <= usize::MAX as u64);
983
984 let mut offset = 0usize;
985 for elem in self.vector.iter_mut() {
986 let next_offset = offset + elem.len();
987 elem.copy_from_slice(&slice[offset..next_offset]);
988 offset = next_offset;
989 }
990 }
991}
992
993#[cfg(feature = "vm-memory")]
994impl<'a> IoVectorMut<'a> {
995 pub fn from_volatile_slice<
1000 B: vm_memory::bitmap::BitmapSlice,
1001 I: IntoIterator<
1002 Item: ImagoAsRef<'a, vm_memory::VolatileSlice<'a, B>>,
1003 IntoIter: ExactSizeIterator,
1004 >,
1005 >(
1006 slices: I,
1007 ) -> (
1008 Self,
1009 VolatileSliceGuard<'a, vm_memory::volatile_memory::PtrGuardMut, B>,
1010 ) {
1011 let slices = slices.into_iter();
1012 let slice_count = slices.len();
1013 let mut ptr_guards = Vec::with_capacity(slice_count);
1014 let mut dirty_on_drop = Vec::with_capacity(slice_count);
1015
1016 for slice in slices {
1017 let slice = slice.as_ref();
1018 ptr_guards.push(slice.ptr_guard_mut());
1019 dirty_on_drop.push((slice.bitmap(), slice.len()));
1021 }
1022
1023 let buffers = ptr_guards
1024 .iter()
1025 .map(|pg| {
1026 let slice = if pg.len() == 0 {
1027 &mut []
1028 } else {
1029 unsafe { std::slice::from_raw_parts_mut(pg.as_ptr(), pg.len()) }
1032 };
1033 IoSliceMut::new(slice)
1034 })
1035 .collect::<Vec<_>>();
1036
1037 let vector = IoVectorMut::from(buffers);
1038 let guard = VolatileSliceGuard {
1039 _ptr_guards: ptr_guards,
1040 dirty_on_drop: Some(dirty_on_drop),
1041 };
1042
1043 (vector, guard)
1044 }
1045}
1046
1047impl<'a> From<&'a Vec<u8>> for IoVector<'a> {
1048 fn from(vec: &'a Vec<u8>) -> Self {
1049 vec.as_slice().into()
1050 }
1051}
1052
1053impl<'a> From<&'a IoBuffer> for IoVector<'a> {
1054 fn from(buf: &'a IoBuffer) -> Self {
1055 buf.as_ref().into_slice().into()
1056 }
1057}
1058
1059impl<'a> From<&'a mut Vec<u8>> for IoVectorMut<'a> {
1060 fn from(vec: &'a mut Vec<u8>) -> Self {
1061 vec.as_mut_slice().into()
1062 }
1063}
1064
1065impl<'a> From<&'a mut IoBuffer> for IoVectorMut<'a> {
1066 fn from(buf: &'a mut IoBuffer) -> Self {
1067 buf.as_mut().into_slice().into()
1068 }
1069}
1070
1071#[cfg(feature = "vm-memory")]
1079pub struct VolatileSliceGuard<'a, PtrGuardType, BitmapType: vm_memory::bitmap::Bitmap> {
1080 _ptr_guards: Vec<PtrGuardType>,
1082
1083 dirty_on_drop: Option<Vec<(&'a BitmapType, usize)>>,
1088}
1089
1090#[cfg(feature = "vm-memory")]
1091impl<P, B: vm_memory::bitmap::Bitmap> Drop for VolatileSliceGuard<'_, P, B> {
1092 fn drop(&mut self) {
1093 if let Some(dirty_on_drop) = self.dirty_on_drop.take() {
1094 for (bitmap, len) in dirty_on_drop {
1095 bitmap.mark_dirty(0, len);
1098 }
1099 }
1100 }
1101}
1102
1103#[cfg(all(test, feature = "vm-memory"))]
1104mod vm_memory_test {
1105 use crate::io_buffers::{IoVector, IoVectorMut};
1106 use vm_memory::bitmap::BitmapSlice;
1107 use vm_memory::VolatileSlice;
1108
1109 pub fn do_test_volatile_slice_owned<B: BitmapSlice>(slices: &[VolatileSlice<B>]) {
1110 {
1111 let _vec = IoVector::from_volatile_slice(slices);
1112 }
1113 {
1114 let _vec = IoVectorMut::from_volatile_slice(slices);
1115 }
1116 }
1117
1118 #[test]
1119 fn test_volatile_slice_owned() {
1120 let empty: Vec<VolatileSlice<()>> = Vec::new();
1121 do_test_volatile_slice_owned(&empty);
1122 }
1123
1124 pub fn do_test_volatile_slice_ref<B: BitmapSlice>(slices: &[&VolatileSlice<B>]) {
1125 {
1126 let _vec = IoVector::from_volatile_slice(slices);
1127 }
1128 {
1129 let _vec = IoVectorMut::from_volatile_slice(slices);
1130 }
1131 }
1132
1133 #[test]
1134 fn test_volatile_slice_ref() {
1135 let empty: Vec<&vm_memory::VolatileSlice<()>> = Vec::new();
1136 do_test_volatile_slice_ref(&empty);
1137 }
1138}