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 unsafe { slice::from_raw_parts(self.as_ptr() as *const T, self.len() / size_of::<T>()) }
267 }
268
269 pub fn split_at(self, mid: usize) -> (IoBufferRef<'a>, IoBufferRef<'a>) {
275 let head_len = cmp::min(mid, self.size);
276
277 (
278 IoBufferRef {
279 pointer: self.pointer,
280 size: head_len,
281 _lifetime: PhantomData,
282 },
283 IoBufferRef {
284 pointer: unsafe { self.pointer.add(head_len) },
286 size: self.size - head_len,
287 _lifetime: PhantomData,
288 },
289 )
290 }
291
292 pub fn into_ref(self) -> IoBufferRef<'a> {
294 self
295 }
296}
297
298impl<'a> IoBufferRefTrait<'a> for IoBufferRef<'a> {
299 type SliceType<T: Copy + Sized + 'a> = &'a [T];
300 type PointerType<T: Copy + Sized + 'a> = *const T;
301
302 passthrough_trait_fn! { fn from_slice(slice: Self::SliceType<u8>) -> Self; }
303 passthrough_trait_fn! { fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>; }
304 passthrough_trait_fn! { fn len(&self) -> usize; }
305 passthrough_trait_fn! { fn as_ptr(&self) -> Self::PointerType<u8>; }
306 passthrough_trait_fn! { fn split_at(self, mid: usize) -> (Self, Self); }
307 passthrough_trait_fn! { fn into_ref(self) -> IoBufferRef<'a>; }
308
309 unsafe fn into_typed_slice<T: Copy + Sized>(self) -> Self::SliceType<T> {
310 unsafe { Self::into_typed_slice(self) }
312 }
313}
314
315impl<'a> From<IoSlice<'a>> for IoBufferRef<'a> {
316 fn from(slice: IoSlice<'a>) -> Self {
317 IoBufferRef {
318 pointer: slice.as_ptr(),
319 size: slice.len(),
320 _lifetime: PhantomData,
321 }
322 }
323}
324
325impl<'a> From<IoBufferRef<'a>> for IoSlice<'a> {
326 fn from(buf: IoBufferRef<'a>) -> Self {
327 IoSlice::new(buf.into_slice())
328 }
329}
330
331impl<'a> IoBufferMut<'a> {
332 pub fn from_slice(slice: &'a mut [u8]) -> Self {
334 IoBufferMut {
335 pointer: slice.as_mut_ptr(),
336 size: size_of_val(slice),
337 _lifetime: PhantomData,
338 }
339 }
340
341 pub fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer> {
343 let mut new_buf = IoBuffer::new(self.len(), alignment)?;
344 new_buf
345 .as_mut()
346 .into_slice()
347 .copy_from_slice(self.into_slice());
348 Ok(new_buf)
349 }
350
351 pub fn len(&self) -> usize {
353 self.size
354 }
355
356 pub fn is_empty(&self) -> bool {
358 self.len() == 0
359 }
360
361 pub fn as_ptr(&self) -> *mut u8 {
363 self.pointer
364 }
365
366 pub fn into_slice(self) -> &'a mut [u8] {
372 unsafe { self.into_typed_slice::<u8>() }
374 }
375
376 pub unsafe fn into_typed_slice<T: Copy + Sized>(self) -> &'a mut [T] {
382 unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut T, self.len() / size_of::<T>()) }
385 }
386
387 pub fn split_at(self, mid: usize) -> (IoBufferMut<'a>, IoBufferMut<'a>) {
393 let head_len = cmp::min(mid, self.size);
394
395 (
396 IoBufferMut {
397 pointer: self.pointer,
398 size: head_len,
399 _lifetime: PhantomData,
400 },
401 IoBufferMut {
402 pointer: unsafe { self.pointer.add(head_len) },
404 size: self.size - head_len,
405 _lifetime: PhantomData,
406 },
407 )
408 }
409
410 pub fn into_ref(self) -> IoBufferRef<'a> {
412 IoBufferRef {
413 pointer: self.pointer,
414 size: self.size,
415 _lifetime: PhantomData,
416 }
417 }
418}
419
420impl<'a> IoBufferRefTrait<'a> for IoBufferMut<'a> {
421 type SliceType<T: Copy + Sized + 'a> = &'a mut [T];
422 type PointerType<T: Copy + Sized + 'a> = *mut T;
423
424 passthrough_trait_fn! { fn from_slice(slice: Self::SliceType<u8>) -> Self; }
425 passthrough_trait_fn! { fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>; }
426 passthrough_trait_fn! { fn len(&self) -> usize; }
427 passthrough_trait_fn! { fn as_ptr(&self) -> Self::PointerType<u8>; }
428 passthrough_trait_fn! { fn split_at(self, mid: usize) -> (Self, Self); }
429 passthrough_trait_fn! { fn into_ref(self) -> IoBufferRef<'a>; }
430
431 unsafe fn into_typed_slice<T: Copy + Sized>(self) -> Self::SliceType<T> {
432 unsafe { Self::into_typed_slice(self) }
434 }
435}
436
437impl<'a, T: Sized> From<&'a mut [T]> for IoBufferMut<'a> {
438 fn from(slice: &'a mut [T]) -> Self {
439 IoBufferMut {
440 pointer: slice.as_mut_ptr() as *mut u8,
441 size: size_of_val(slice),
442 _lifetime: PhantomData,
443 }
444 }
445}
446
447impl<'a> From<IoSliceMut<'a>> for IoBufferMut<'a> {
448 fn from(mut slice: IoSliceMut<'a>) -> Self {
449 IoBufferMut {
450 pointer: slice.as_mut_ptr(),
451 size: slice.len(),
452 _lifetime: PhantomData,
453 }
454 }
455}
456
457impl<'a> From<IoBufferMut<'a>> for IoSliceMut<'a> {
458 fn from(buf: IoBufferMut<'a>) -> Self {
459 IoSliceMut::new(buf.into_slice())
460 }
461}
462
463#[allow(dead_code)]
465pub(crate) trait IoVectorTrait: Sized {
466 type SliceType;
468
469 type BufferType;
471
472 fn new() -> Self;
474
475 fn with_capacity(cap: usize) -> Self;
479
480 fn push(&mut self, slice: Self::SliceType);
482
483 fn push_ioslice(&mut self, ioslice: Self::BufferType);
485
486 fn insert(&mut self, index: usize, slice: Self::SliceType);
488
489 fn len(&self) -> u64;
491
492 fn buffer_count(&self) -> usize;
494
495 fn is_empty(&self) -> bool {
499 debug_assert!((self.len() == 0) == (self.buffer_count() == 0));
500 self.len() == 0
501 }
502
503 fn append(&mut self, other: Self);
505
506 fn split_at(self, mid: u64) -> (Self, Self);
511
512 fn split_tail_at(self, mid: u64) -> Self;
517
518 fn copy_into_slice(&self, slice: &mut [u8]);
522
523 fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>;
525
526 #[cfg(unix)]
532 unsafe fn as_iovec<'a>(&'a self) -> &'a [libc::iovec]
533 where
534 Self: 'a;
535
536 fn is_aligned(&self, mem_alignment: usize, req_alignment: usize) -> bool;
541
542 fn into_inner(self) -> Vec<Self::BufferType>;
544}
545
546macro_rules! impl_io_vector {
548 ($type:tt, $inner_type:tt, $buffer_type:tt, $slice_type:ty, $slice_type_lifetime_b:ty) => {
549 pub struct $type<'a> {
551 vector: Vec<$inner_type<'a>>,
553
554 total_size: u64,
556 }
557
558 impl<'a> $type<'a> {
559 pub fn new() -> Self {
561 Self::default()
562 }
563
564 pub fn with_capacity(cap: usize) -> Self {
568 $type {
569 vector: Vec::with_capacity(cap),
570 total_size: 0,
571 }
572 }
573
574 pub fn push(&mut self, slice: $slice_type) {
576 debug_assert!(!slice.is_empty());
577 self.total_size += slice.len() as u64;
578 self.vector.push($inner_type::new(slice));
579 }
580
581 pub fn push_ioslice(&mut self, ioslice: $inner_type<'a>) {
583 debug_assert!(!ioslice.is_empty());
584 self.total_size += ioslice.len() as u64;
585 self.vector.push(ioslice);
586 }
587
588 pub fn insert(&mut self, index: usize, slice: $slice_type) {
590 debug_assert!(!slice.is_empty());
591 self.total_size += slice.len() as u64;
592 self.vector.insert(index, $inner_type::new(slice));
593 }
594
595 pub fn len(&self) -> u64 {
597 self.total_size
598 }
599
600 pub fn buffer_count(&self) -> usize {
602 self.vector.len()
603 }
604
605 pub fn is_empty(&self) -> bool {
609 debug_assert!((self.len() == 0) == (self.buffer_count() == 0));
610 self.len() == 0
611 }
612
613 pub fn append(&mut self, mut other: Self) {
615 self.total_size += other.total_size;
616 self.vector.append(&mut other.vector);
617 }
618
619 pub fn split_at(self, mid: u64) -> (Self, Self) {
624 let (head, tail) = self.do_split_at(mid, true);
625 (head.unwrap(), tail)
626 }
627
628 pub fn split_tail_at(self, mid: u64) -> Self {
633 self.do_split_at(mid, false).1
634 }
635
636 pub fn copy_into_slice(&self, slice: &mut [u8]) {
640 if slice.len() as u64 != self.total_size {
641 panic!("IoVectorTrait::copy_into_slice() called on a slice of different length from the vector");
642 }
643
644 assert!(self.total_size <= usize::MAX as u64);
645
646 let mut offset = 0usize;
647 for elem in self.vector.iter() {
648 let next_offset = offset + elem.len();
649 slice[offset..next_offset].copy_from_slice(&elem[..]);
650 offset = next_offset;
651 }
652 }
653
654 pub fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer> {
656 let size = self.total_size.try_into().map_err(|_| {
657 io::Error::other(format!("Buffer is too big ({})", self.total_size))
658 })?;
659 let mut new_buf = IoBuffer::new(size, alignment)?;
660 self.copy_into_slice(new_buf.as_mut().into_slice());
661 Ok(new_buf)
662 }
663
664 #[cfg(unix)]
670 pub unsafe fn as_iovec<'b>(&'b self) -> &'b [libc::iovec] where Self: 'b {
671 unsafe {
674 mem::transmute::<&'b [$inner_type<'b>], &'b [libc::iovec]>(&self.vector[..])
675 }
676 }
677
678 pub fn is_aligned(&self, mem_alignment: usize, req_alignment: usize) -> bool {
684 if mem_alignment == 1 && req_alignment == 1 {
686 return true;
687 }
688
689 debug_assert!(mem_alignment.is_power_of_two() && req_alignment.is_power_of_two());
690 let base_align_mask = mem_alignment - 1;
691 let len_align_mask = base_align_mask | (req_alignment - 1);
692
693 self.vector.iter().all(|buf| {
694 buf.as_ptr() as usize & base_align_mask == 0 &&
695 buf.len() & len_align_mask == 0
696 })
697 }
698
699 pub fn into_inner(self) -> Vec<$inner_type<'a>> {
701 self.vector
702 }
703
704 pub fn with_pushed<'b>(self, slice: $slice_type_lifetime_b) -> $type<'b>
709 where
710 'a: 'b,
711 {
712 let mut vec: $type<'b> = self;
713 vec.push(slice);
714 vec
715 }
716
717 pub fn with_inserted<'b>(self, index: usize, slice: $slice_type_lifetime_b) -> $type<'b>
722 where
723 'a: 'b,
724 {
725 let mut vec: $type<'b> = self;
726 vec.insert(index, slice);
727 vec
728 }
729
730 fn do_split_at(mut self, mid: u64, keep_head: bool) -> (Option<$type<'a>>, $type<'a>) {
735 if mid >= self.total_size {
736 return (
738 keep_head.then_some(self),
739 $type {
740 vector: Vec::new(),
741 total_size: 0,
742 },
743 );
744 }
745
746 let mut i = 0; let mut offset = 0u64; let (vec_head, vec_tail) = loop {
749 if offset == mid {
750 if keep_head {
752 let mut vec_head = self.vector;
753 let vec_tail = vec_head.split_off(i);
754 break (Some(vec_head), vec_tail);
755 } else {
756 break (None, self.vector.split_off(i));
757 }
758 }
759
760 let post_elm_offset = offset + self.vector[i].len() as u64;
761
762 if post_elm_offset > mid {
763 let mut vec_head = self.vector;
766 let mut tail_iter = vec_head.drain(i..);
767
768 let mid_elm = tail_iter.next().unwrap();
770 let mid_elm: $buffer_type<'a> = mid_elm.into();
771
772 let mid_elm_head_len: usize = (mid - offset).try_into().unwrap();
774 let (mid_head, mid_tail) = mid_elm.split_at(mid_elm_head_len);
775
776 let mut vec_tail: Vec<$inner_type<'a>> = vec![mid_tail.into()];
777 vec_tail.extend(tail_iter);
778
779 if keep_head {
780 vec_head.push(mid_head.into());
781 break (Some(vec_head), vec_tail);
782 } else {
783 break (None, vec_tail);
784 }
785 }
786
787 offset = post_elm_offset;
788
789 i += 1;
790 assert!(i < self.vector.len());
793 };
794
795 let head = keep_head.then(|| $type {
796 vector: vec_head.unwrap(),
797 total_size: mid,
798 });
799 let tail = $type {
800 vector: vec_tail,
801 total_size: self.total_size - mid,
802 };
803
804 (head, tail)
805 }
806 }
807
808 impl<'a> IoVectorTrait for $type<'a> {
809 type SliceType = $slice_type;
810 type BufferType = $inner_type<'a>;
811
812 passthrough_trait_fn! { fn new() -> Self; }
813 passthrough_trait_fn! { fn with_capacity(cap: usize) -> Self; }
814 passthrough_trait_fn! { fn push(&mut self, slice: Self::SliceType); }
815 passthrough_trait_fn! { fn push_ioslice(&mut self, ioslice: Self::BufferType); }
816 passthrough_trait_fn! { fn insert(&mut self, index: usize, slice: Self::SliceType); }
817 passthrough_trait_fn! { fn len(&self) -> u64; }
818 passthrough_trait_fn! { fn buffer_count(&self) -> usize; }
819 passthrough_trait_fn! { fn append(&mut self, other: Self); }
820 passthrough_trait_fn! { fn split_at(self, mid: u64) -> (Self, Self); }
821 passthrough_trait_fn! { fn split_tail_at(self, mid: u64) -> Self; }
822 passthrough_trait_fn! { fn copy_into_slice(&self, slice: &mut [u8]); }
823 passthrough_trait_fn! { fn try_into_owned(self, alignment: usize) -> io::Result<IoBuffer>; }
824 passthrough_trait_fn! { fn is_aligned(&self, mem_alignment: usize, req_alignment: usize) -> bool; }
825 passthrough_trait_fn! { fn into_inner(self) -> Vec<Self::BufferType>; }
826
827 #[cfg(unix)]
828 unsafe fn as_iovec<'b>(&'b self) -> &'b [libc::iovec]
829 where
830 Self: 'b
831 {
832 unsafe { Self::as_iovec(self) }
834 }
835 }
836
837 impl<'a> From<Vec<$inner_type<'a>>> for $type<'a> {
838 fn from(vector: Vec<$inner_type<'a>>) -> Self {
839 let total_size = vector
840 .iter()
841 .map(|e| e.len())
842 .fold(0u64, |sum, e| sum + e as u64);
843
844 $type { vector, total_size }
845 }
846 }
847
848 impl<'a> From<$buffer_type<'a>> for $type<'a> {
849 fn from(buffer: $buffer_type<'a>) -> Self {
850 let total_size = buffer.len() as u64;
851 if total_size > 0 {
852 $type {
853 vector: vec![buffer.into()],
854 total_size,
855 }
856 } else {
857 $type {
858 vector: Vec::new(),
859 total_size: 0,
860 }
861 }
862 }
863 }
864
865 impl<'a> From<$slice_type> for $type<'a> {
866 fn from(slice: $slice_type) -> Self {
867 let total_size = slice.len() as u64;
868 if total_size > 0 {
869 $type {
870 vector: vec![$inner_type::new(slice)],
871 total_size,
872 }
873 } else {
874 $type {
875 vector: Vec::new(),
876 total_size: 0,
877 }
878 }
879 }
880 }
881
882 impl<'a> Default for $type<'a> {
883 fn default() -> Self {
884 $type {
885 vector: Vec::new(),
886 total_size: 0,
887 }
888 }
889 }
890
891 impl Debug for $type<'_> {
892 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
893 f.debug_struct(std::stringify!($type))
894 .field("vector.len()", &self.vector.len())
895 .field("total_size", &self.total_size)
896 .finish()
897 }
898 }
899 };
900}
901
902impl_io_vector!(IoVector, IoSlice, IoBufferRef, &'a [u8], &'b [u8]);
903impl_io_vector!(
904 IoVectorMut,
905 IoSliceMut,
906 IoBufferMut,
907 &'a mut [u8],
908 &'b mut [u8]
909);
910
911#[cfg(feature = "vm-memory")]
912impl<'a> IoVector<'a> {
913 pub fn from_volatile_slice<
918 B: vm_memory::bitmap::BitmapSlice,
919 I: IntoIterator<
920 Item: ImagoAsRef<'a, vm_memory::VolatileSlice<'a, B>>,
921 IntoIter: ExactSizeIterator,
922 >,
923 >(
924 slices: I,
925 ) -> (
926 Self,
927 VolatileSliceGuard<'a, vm_memory::volatile_memory::PtrGuard, B>,
928 ) {
929 let ptr_guards = slices
930 .into_iter()
931 .map(|slice| slice.as_ref().ptr_guard())
932 .collect::<Vec<_>>();
933 let buffers = ptr_guards
934 .iter()
935 .map(|pg| {
936 let slice = unsafe { std::slice::from_raw_parts(pg.as_ptr(), pg.len()) };
939 IoSlice::new(slice)
940 })
941 .collect::<Vec<_>>();
942
943 let vector = IoVector::from(buffers);
944 let guard = VolatileSliceGuard {
945 _ptr_guards: ptr_guards,
946 dirty_on_drop: None,
948 };
949
950 (vector, guard)
951 }
952}
953
954impl IoVectorMut<'_> {
955 pub fn fill(&mut self, value: u8) {
957 for slice in self.vector.iter_mut() {
958 slice.fill(value);
959 }
960 }
961
962 pub fn copy_from_slice(&mut self, slice: &[u8]) {
966 if slice.len() as u64 != self.total_size {
967 panic!("IoVectorMut::copy_from_slice() called on a slice of different length from the vector");
968 }
969
970 assert!(self.total_size <= usize::MAX as u64);
971
972 let mut offset = 0usize;
973 for elem in self.vector.iter_mut() {
974 let next_offset = offset + elem.len();
975 elem.copy_from_slice(&slice[offset..next_offset]);
976 offset = next_offset;
977 }
978 }
979}
980
981#[cfg(feature = "vm-memory")]
982impl<'a> IoVectorMut<'a> {
983 pub fn from_volatile_slice<
988 B: vm_memory::bitmap::BitmapSlice,
989 I: IntoIterator<
990 Item: ImagoAsRef<'a, vm_memory::VolatileSlice<'a, B>>,
991 IntoIter: ExactSizeIterator,
992 >,
993 >(
994 slices: I,
995 ) -> (
996 Self,
997 VolatileSliceGuard<'a, vm_memory::volatile_memory::PtrGuardMut, B>,
998 ) {
999 let slices = slices.into_iter();
1000 let slice_count = slices.len();
1001 let mut ptr_guards = Vec::with_capacity(slice_count);
1002 let mut dirty_on_drop = Vec::with_capacity(slice_count);
1003
1004 for slice in slices {
1005 let slice = slice.as_ref();
1006 ptr_guards.push(slice.ptr_guard_mut());
1007 dirty_on_drop.push((slice.bitmap(), slice.len()));
1009 }
1010
1011 let buffers = ptr_guards
1012 .iter()
1013 .map(|pg| {
1014 let slice = unsafe { std::slice::from_raw_parts_mut(pg.as_ptr(), pg.len()) };
1017 IoSliceMut::new(slice)
1018 })
1019 .collect::<Vec<_>>();
1020
1021 let vector = IoVectorMut::from(buffers);
1022 let guard = VolatileSliceGuard {
1023 _ptr_guards: ptr_guards,
1024 dirty_on_drop: Some(dirty_on_drop),
1025 };
1026
1027 (vector, guard)
1028 }
1029}
1030
1031impl<'a> From<&'a Vec<u8>> for IoVector<'a> {
1032 fn from(vec: &'a Vec<u8>) -> Self {
1033 vec.as_slice().into()
1034 }
1035}
1036
1037impl<'a> From<&'a IoBuffer> for IoVector<'a> {
1038 fn from(buf: &'a IoBuffer) -> Self {
1039 buf.as_ref().into_slice().into()
1040 }
1041}
1042
1043impl<'a> From<&'a mut Vec<u8>> for IoVectorMut<'a> {
1044 fn from(vec: &'a mut Vec<u8>) -> Self {
1045 vec.as_mut_slice().into()
1046 }
1047}
1048
1049impl<'a> From<&'a mut IoBuffer> for IoVectorMut<'a> {
1050 fn from(buf: &'a mut IoBuffer) -> Self {
1051 buf.as_mut().into_slice().into()
1052 }
1053}
1054
1055#[cfg(feature = "vm-memory")]
1063pub struct VolatileSliceGuard<'a, PtrGuardType, BitmapType: vm_memory::bitmap::Bitmap> {
1064 _ptr_guards: Vec<PtrGuardType>,
1066
1067 dirty_on_drop: Option<Vec<(&'a BitmapType, usize)>>,
1072}
1073
1074#[cfg(feature = "vm-memory")]
1075impl<P, B: vm_memory::bitmap::Bitmap> Drop for VolatileSliceGuard<'_, P, B> {
1076 fn drop(&mut self) {
1077 if let Some(dirty_on_drop) = self.dirty_on_drop.take() {
1078 for (bitmap, len) in dirty_on_drop {
1079 bitmap.mark_dirty(0, len);
1082 }
1083 }
1084 }
1085}
1086
1087#[cfg(all(test, feature = "vm-memory"))]
1088mod vm_memory_test {
1089 use crate::io_buffers::{IoVector, IoVectorMut};
1090 use vm_memory::bitmap::BitmapSlice;
1091 use vm_memory::VolatileSlice;
1092
1093 pub fn do_test_volatile_slice_owned<B: BitmapSlice>(slices: &[VolatileSlice<B>]) {
1094 {
1095 let _vec = IoVector::from_volatile_slice(slices);
1096 }
1097 {
1098 let _vec = IoVectorMut::from_volatile_slice(slices);
1099 }
1100 }
1101
1102 #[test]
1103 fn test_volatile_slice_owned() {
1104 let empty: Vec<VolatileSlice<()>> = Vec::new();
1105 do_test_volatile_slice_owned(&empty);
1106 }
1107
1108 pub fn do_test_volatile_slice_ref<B: BitmapSlice>(slices: &[&VolatileSlice<B>]) {
1109 {
1110 let _vec = IoVector::from_volatile_slice(slices);
1111 }
1112 {
1113 let _vec = IoVectorMut::from_volatile_slice(slices);
1114 }
1115 }
1116
1117 #[test]
1118 fn test_volatile_slice_ref() {
1119 let empty: Vec<&vm_memory::VolatileSlice<()>> = Vec::new();
1120 do_test_volatile_slice_ref(&empty);
1121 }
1122}