1use std::any::Any;
18use std::collections::VecDeque;
19use std::io::{self, IoSlice, Read};
20use std::marker::PhantomData;
21use std::mem::{size_of, MaybeUninit};
22use std::ptr::copy_nonoverlapping;
23use std::{cmp, fmt};
24
25use lazy_static::lazy_static;
26use libc::{sysconf, _SC_PAGESIZE};
27use vm_memory::{ByteValued, VolatileSlice};
28
29#[cfg(feature = "async-io")]
30use crate::file_buf::FileVolatileBuf;
31use crate::file_buf::FileVolatileSlice;
32#[cfg(feature = "async-io")]
33use crate::file_traits::AsyncFileReadWriteVolatile;
34use crate::file_traits::FileReadWriteVolatile;
35use crate::BitmapSlice;
36
37mod fs_cache_req_handler;
38#[cfg(feature = "fusedev")]
39mod fusedev;
40#[cfg(feature = "virtiofs")]
41mod virtiofs;
42
43pub use self::fs_cache_req_handler::FsCacheReqHandler;
44#[cfg(feature = "fusedev")]
45pub use self::fusedev::{FuseBuf, FuseChannel, FuseDevWriter, FuseSession};
46#[cfg(feature = "virtiofs")]
47pub use self::virtiofs::VirtioFsWriter;
48
49#[derive(Debug)]
51pub enum Error {
52 DescriptorChainOverflow,
54 FindMemoryRegion,
56 InvalidChain,
58 InvalidParameter,
60 IoError(io::Error),
62 SplitOutOfBounds(usize),
64 VolatileMemoryError(vm_memory::VolatileMemoryError),
66 #[cfg(feature = "fusedev")]
67 SessionFailure(String),
69 #[cfg(feature = "virtiofs")]
70 GuestMemoryError(vm_memory::GuestMemoryError),
72 #[cfg(feature = "virtiofs")]
73 ConvertIndirectDescriptor(virtio_queue::Error),
75}
76
77impl fmt::Display for Error {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 use self::Error::*;
80
81 match self {
82 DescriptorChainOverflow => write!(
83 f,
84 "the combined length of all the buffers in a `DescriptorChain` would overflow"
85 ),
86 FindMemoryRegion => write!(f, "no memory region for this address range"),
87 InvalidChain => write!(f, "invalid descriptor chain"),
88 InvalidParameter => write!(f, "invalid parameter"),
89 IoError(e) => write!(f, "descriptor I/O error: {e}"),
90 SplitOutOfBounds(off) => write!(f, "`DescriptorChain` split is out of bounds: {off}"),
91 VolatileMemoryError(e) => write!(f, "volatile memory error: {e}"),
92
93 #[cfg(feature = "fusedev")]
94 SessionFailure(e) => write!(f, "fuse session failure: {e}"),
95
96 #[cfg(feature = "virtiofs")]
97 ConvertIndirectDescriptor(e) => write!(f, "invalid indirect descriptor: {e}"),
98 #[cfg(feature = "virtiofs")]
99 GuestMemoryError(e) => write!(f, "descriptor guest memory error: {e}"),
100 }
101 }
102}
103
104impl From<Box<dyn Any + Send>> for Error {
105 fn from(value: Box<dyn Any + Send>) -> Self {
106 let err = value.downcast::<Error>().unwrap();
107 *err
108 }
109}
110
111pub type Result<T> = std::result::Result<T, Error>;
113
114impl std::error::Error for Error {}
115
116#[derive(Clone)]
117struct IoBuffers<'a, S> {
118 buffers: VecDeque<VolatileSlice<'a, S>>,
119 bytes_consumed: usize,
120}
121
122impl<S: BitmapSlice> Default for IoBuffers<'_, S> {
123 fn default() -> Self {
124 IoBuffers {
125 buffers: VecDeque::new(),
126 bytes_consumed: 0,
127 }
128 }
129}
130
131impl<S: BitmapSlice> IoBuffers<'_, S> {
132 fn available_bytes(&self) -> usize {
133 self.buffers
137 .iter()
138 .fold(0usize, |count, buf| count + buf.len())
139 }
140
141 fn bytes_consumed(&self) -> usize {
142 self.bytes_consumed
143 }
144
145 fn allocate_file_volatile_slice(&self, count: usize) -> Vec<FileVolatileSlice> {
146 let mut rem = count;
147 let mut bufs: Vec<FileVolatileSlice> = Vec::with_capacity(self.buffers.len());
148
149 for buf in &self.buffers {
150 if rem == 0 {
151 break;
152 }
153
154 let local_buf = if buf.len() > rem {
157 FileVolatileSlice::from_volatile_slice(&buf.subslice(0, rem).unwrap())
159 } else {
160 FileVolatileSlice::from_volatile_slice(buf)
161 };
162 bufs.push(local_buf);
163
164 rem -= local_buf.len();
166 }
167
168 bufs
169 }
170
171 #[cfg(feature = "async-io")]
172 unsafe fn prepare_io_buf(&self, count: usize) -> Vec<FileVolatileBuf> {
173 let mut rem = count;
174 let mut bufs = Vec::with_capacity(self.buffers.len());
175
176 for buf in &self.buffers {
177 if rem == 0 {
178 break;
179 }
180
181 let local_buf = if buf.len() > rem {
184 buf.subslice(0, rem).unwrap()
186 } else {
187 buf.clone()
188 };
189 bufs.push(FileVolatileBuf::from_raw_ptr(
191 local_buf.as_ptr(),
192 local_buf.len(),
193 local_buf.len(),
194 ));
195
196 rem -= local_buf.len() as usize;
198 }
199
200 bufs
201 }
202
203 #[cfg(all(feature = "async-io", feature = "virtiofs"))]
204 unsafe fn prepare_mut_io_buf(&self, count: usize) -> Vec<FileVolatileBuf> {
205 let mut rem = count;
206 let mut bufs = Vec::with_capacity(self.buffers.len());
207
208 for buf in &self.buffers {
209 if rem == 0 {
210 break;
211 }
212
213 let local_buf = if buf.len() > rem {
216 buf.subslice(0, rem).unwrap()
218 } else {
219 buf.clone()
220 };
221 bufs.push(FileVolatileBuf::from_raw_ptr(
222 local_buf.as_ptr(),
223 0,
224 local_buf.len(),
225 ));
226
227 rem -= local_buf.len() as usize;
229 }
230
231 bufs
232 }
233
234 fn mark_dirty(&self, count: usize) {
235 let mut rem = count;
236
237 for buf in &self.buffers {
238 if rem == 0 {
239 break;
240 }
241
242 let local_buf = if buf.len() > rem {
245 buf.subslice(0, rem).unwrap()
247 } else {
248 buf.clone()
249 };
250 local_buf.bitmap().mark_dirty(0, local_buf.len());
251
252 rem -= local_buf.len();
254 }
255 }
256
257 fn mark_used(&mut self, bytes_consumed: usize) -> io::Result<()> {
258 let total_bytes_consumed =
261 self.bytes_consumed
262 .checked_add(bytes_consumed)
263 .ok_or_else(|| {
264 io::Error::new(io::ErrorKind::InvalidData, Error::DescriptorChainOverflow)
265 })?;
266
267 let mut rem = bytes_consumed;
268 while let Some(buf) = self.buffers.pop_front() {
269 if rem < buf.len() {
270 self.buffers.push_front(buf.offset(rem).unwrap());
274 break;
275 }
276
277 rem -= buf.len();
279 }
280
281 self.bytes_consumed = total_bytes_consumed;
282
283 Ok(())
284 }
285
286 fn consume<F>(&mut self, mark_dirty: bool, count: usize, f: F) -> io::Result<usize>
296 where
297 F: FnOnce(&[FileVolatileSlice]) -> io::Result<usize>,
298 {
299 let bufs = self.allocate_file_volatile_slice(count);
300 if bufs.is_empty() {
301 Ok(0)
302 } else {
303 let bytes_consumed = f(&bufs)?;
304 if mark_dirty {
305 self.mark_dirty(bytes_consumed);
306 }
307 self.mark_used(bytes_consumed)?;
308 Ok(bytes_consumed)
309 }
310 }
311
312 fn consume_for_read<F>(&mut self, count: usize, f: F) -> io::Result<usize>
313 where
314 F: FnOnce(&[FileVolatileSlice]) -> io::Result<usize>,
315 {
316 self.consume(false, count, f)
317 }
318
319 fn split_at(&mut self, offset: usize) -> Result<Self> {
320 let mut rem = offset;
321 let pos = self.buffers.iter().position(|buf| {
322 if rem < buf.len() {
323 true
324 } else {
325 rem -= buf.len();
326 false
327 }
328 });
329
330 if let Some(at) = pos {
331 let mut other = self.buffers.split_off(at);
332
333 if rem > 0 {
334 let front = other.pop_front().expect("empty VecDeque after split");
337 self.buffers
338 .push_back(front.subslice(0, rem).map_err(Error::VolatileMemoryError)?);
339 other.push_front(front.offset(rem).map_err(Error::VolatileMemoryError)?);
340 }
341
342 Ok(IoBuffers {
343 buffers: other,
344 bytes_consumed: 0,
345 })
346 } else if rem == 0 {
347 Ok(IoBuffers {
348 buffers: VecDeque::new(),
349 bytes_consumed: 0,
350 })
351 } else {
352 Err(Error::SplitOutOfBounds(offset))
353 }
354 }
355}
356
357#[derive(Clone)]
364pub struct Reader<'a, S = ()> {
365 buffers: IoBuffers<'a, S>,
366}
367
368impl<S: BitmapSlice> Default for Reader<'_, S> {
369 fn default() -> Self {
370 Reader {
371 buffers: IoBuffers::default(),
372 }
373 }
374}
375
376impl<S: BitmapSlice> Reader<'_, S> {
377 pub fn read_obj<T: ByteValued>(&mut self) -> io::Result<T> {
379 let mut obj = MaybeUninit::<T>::uninit();
380
381 let buf = unsafe {
384 ::std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::<T>())
385 };
386
387 self.read_exact(buf)?;
388
389 Ok(unsafe { obj.assume_init() })
392 }
393
394 pub fn read_to<F: FileReadWriteVolatile>(
399 &mut self,
400 mut dst: F,
401 count: usize,
402 ) -> io::Result<usize> {
403 self.buffers
404 .consume_for_read(count, |bufs| dst.write_vectored_volatile(bufs))
405 }
406
407 pub fn read_to_at<F: FileReadWriteVolatile>(
412 &mut self,
413 mut dst: F,
414 count: usize,
415 off: u64,
416 ) -> io::Result<usize> {
417 self.buffers
418 .consume_for_read(count, |bufs| dst.write_vectored_at_volatile(bufs, off))
419 }
420
421 pub fn read_exact_to<F: FileReadWriteVolatile>(
423 &mut self,
424 mut dst: F,
425 mut count: usize,
426 ) -> io::Result<()> {
427 while count > 0 {
428 match self.read_to(&mut dst, count) {
429 Ok(0) => {
430 return Err(io::Error::new(
431 io::ErrorKind::UnexpectedEof,
432 "failed to fill whole buffer",
433 ))
434 }
435 Ok(n) => count -= n,
436 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
437 Err(e) => return Err(e),
438 }
439 }
440
441 Ok(())
442 }
443
444 pub fn available_bytes(&self) -> usize {
449 self.buffers.available_bytes()
450 }
451
452 pub fn bytes_read(&self) -> usize {
454 self.buffers.bytes_consumed()
455 }
456
457 pub fn split_at(&mut self, offset: usize) -> Result<Self> {
462 self.buffers
463 .split_at(offset)
464 .map(|buffers| Reader { buffers })
465 }
466}
467
468impl<S: BitmapSlice> io::Read for Reader<'_, S> {
469 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
470 self.buffers.consume_for_read(buf.len(), |bufs| {
471 let mut rem = buf;
472 let mut total = 0;
473 for buf in bufs {
474 let copy_len = cmp::min(rem.len(), buf.len());
475
476 unsafe {
478 copy_nonoverlapping(buf.as_ptr() as *const u8, rem.as_mut_ptr(), copy_len);
479 }
480 rem = &mut rem[copy_len..];
481 total += copy_len;
482 }
483 Ok(total)
484 })
485 }
486}
487
488#[cfg(feature = "async-io")]
489mod async_io {
490 use super::*;
491
492 impl<'a, S: BitmapSlice> Reader<'a, S> {
493 pub async fn async_read_to_at<F: AsyncFileReadWriteVolatile>(
498 &mut self,
499 dst: &F,
500 count: usize,
501 off: u64,
502 ) -> io::Result<usize> {
503 let bufs = unsafe { self.buffers.prepare_io_buf(count) };
505 if bufs.is_empty() {
506 Ok(0)
507 } else {
508 let (res, _) = dst.async_write_vectored_at_volatile(bufs, off).await;
509 match res {
510 Ok(cnt) => {
511 self.buffers.mark_used(cnt)?;
512 Ok(cnt)
513 }
514 Err(e) => Err(e),
515 }
516 }
517 }
518 }
519}
520
521pub enum Writer<'a, S: BitmapSlice = ()> {
523 #[cfg(feature = "fusedev")]
524 FuseDev(FuseDevWriter<'a, S>),
526 #[cfg(feature = "virtiofs")]
527 VirtioFs(VirtioFsWriter<'a, S>),
529 Noop(PhantomData<&'a S>),
531}
532
533impl<'a, S: BitmapSlice> Writer<'a, S> {
534 pub fn write_from_at<F: FileReadWriteVolatile>(
538 &mut self,
539 src: F,
540 count: usize,
541 off: u64,
542 ) -> io::Result<usize> {
543 match self {
544 #[cfg(feature = "fusedev")]
545 Writer::FuseDev(w) => w.write_from_at(src, count, off),
546 #[cfg(feature = "virtiofs")]
547 Writer::VirtioFs(w) => w.write_from_at(src, count, off),
548 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
549 }
550 }
551
552 pub fn split_at(&mut self, offset: usize) -> Result<Self> {
558 match self {
559 #[cfg(feature = "fusedev")]
560 Writer::FuseDev(w) => w.split_at(offset).map(|w| w.into()),
561 #[cfg(feature = "virtiofs")]
562 Writer::VirtioFs(w) => w.split_at(offset).map(|w| w.into()),
563 _ => Err(Error::InvalidParameter),
564 }
565 }
566
567 pub fn available_bytes(&self) -> usize {
572 match self {
573 #[cfg(feature = "fusedev")]
574 Writer::FuseDev(w) => w.available_bytes(),
575 #[cfg(feature = "virtiofs")]
576 Writer::VirtioFs(w) => w.available_bytes(),
577 _ => 0,
578 }
579 }
580
581 pub fn bytes_written(&self) -> usize {
583 match self {
584 #[cfg(feature = "fusedev")]
585 Writer::FuseDev(w) => w.bytes_written(),
586 #[cfg(feature = "virtiofs")]
587 Writer::VirtioFs(w) => w.bytes_written(),
588 _ => 0,
589 }
590 }
591
592 pub fn commit(&mut self, other: Option<&Self>) -> io::Result<usize> {
594 match self {
595 #[cfg(feature = "fusedev")]
596 Writer::FuseDev(w) => w.commit(other),
597 #[cfg(feature = "virtiofs")]
598 Writer::VirtioFs(w) => w.commit(other),
599 _ => Ok(0),
600 }
601 }
602}
603
604impl<'a, S: BitmapSlice> io::Write for Writer<'a, S> {
605 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
606 match self {
607 #[cfg(feature = "fusedev")]
608 Writer::FuseDev(w) => w.write(buf),
609 #[cfg(feature = "virtiofs")]
610 Writer::VirtioFs(w) => w.write(buf),
611 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
612 }
613 }
614
615 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
616 match self {
617 #[cfg(feature = "fusedev")]
618 Writer::FuseDev(w) => w.write_vectored(bufs),
619 #[cfg(feature = "virtiofs")]
620 Writer::VirtioFs(w) => w.write_vectored(bufs),
621 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
622 }
623 }
624
625 fn flush(&mut self) -> io::Result<()> {
626 match self {
627 #[cfg(feature = "fusedev")]
628 Writer::FuseDev(w) => w.flush(),
629 #[cfg(feature = "virtiofs")]
630 Writer::VirtioFs(w) => w.flush(),
631 _ => Ok(()),
632 }
633 }
634}
635
636#[cfg(feature = "async-io")]
637impl<'a, S: BitmapSlice> Writer<'a, S> {
638 pub async fn async_write(&mut self, data: &[u8]) -> io::Result<usize> {
640 match self {
641 #[cfg(feature = "fusedev")]
642 Writer::FuseDev(w) => w.async_write(data).await,
643 #[cfg(feature = "virtiofs")]
644 Writer::VirtioFs(w) => w.async_write(data).await,
645 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
646 }
647 }
648
649 pub async fn async_write2(&mut self, data: &[u8], data2: &[u8]) -> io::Result<usize> {
651 match self {
652 #[cfg(feature = "fusedev")]
653 Writer::FuseDev(w) => w.async_write2(data, data2).await,
654 #[cfg(feature = "virtiofs")]
655 Writer::VirtioFs(w) => w.async_write2(data, data2).await,
656 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
657 }
658 }
659
660 pub async fn async_write3(
662 &mut self,
663 data: &[u8],
664 data2: &[u8],
665 data3: &[u8],
666 ) -> io::Result<usize> {
667 match self {
668 #[cfg(feature = "fusedev")]
669 Writer::FuseDev(w) => w.async_write3(data, data2, data3).await,
670 #[cfg(feature = "virtiofs")]
671 Writer::VirtioFs(w) => w.async_write3(data, data2, data3).await,
672 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
673 }
674 }
675
676 pub async fn async_write_all(&mut self, buf: &[u8]) -> io::Result<()> {
678 match self {
679 #[cfg(feature = "fusedev")]
680 Writer::FuseDev(w) => w.async_write_all(buf).await,
681 #[cfg(feature = "virtiofs")]
682 Writer::VirtioFs(w) => w.async_write_all(buf).await,
683 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
684 }
685 }
686
687 pub async fn async_write_from_at<F: AsyncFileReadWriteVolatile>(
691 &mut self,
692 src: &F,
693 count: usize,
694 off: u64,
695 ) -> io::Result<usize> {
696 match self {
697 #[cfg(feature = "fusedev")]
698 Writer::FuseDev(w) => w.async_write_from_at(src, count, off).await,
699 #[cfg(feature = "virtiofs")]
700 Writer::VirtioFs(w) => w.async_write_from_at(src, count, off).await,
701 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
702 }
703 }
704
705 pub async fn async_commit(&mut self, other: Option<&Writer<'a, S>>) -> io::Result<usize> {
707 match self {
708 #[cfg(feature = "fusedev")]
709 Writer::FuseDev(w) => w.async_commit(other).await,
710 #[cfg(feature = "virtiofs")]
711 Writer::VirtioFs(w) => w.async_commit(other).await,
712 _ => Err(std::io::Error::from_raw_os_error(libc::EINVAL)),
713 }
714 }
715}
716
717#[cfg(feature = "fusedev")]
718impl<'a, S: BitmapSlice> From<FuseDevWriter<'a, S>> for Writer<'a, S> {
719 fn from(w: FuseDevWriter<'a, S>) -> Self {
720 Writer::FuseDev(w)
721 }
722}
723
724#[cfg(feature = "virtiofs")]
725impl<'a, S: BitmapSlice> From<VirtioFsWriter<'a, S>> for Writer<'a, S> {
726 fn from(w: VirtioFsWriter<'a, S>) -> Self {
727 Writer::VirtioFs(w)
728 }
729}
730
731lazy_static! {
732 static ref PAGESIZE: usize = unsafe { sysconf(_SC_PAGESIZE) as usize };
733}
734
735#[inline(always)]
737pub fn pagesize() -> usize {
738 *PAGESIZE
739}
740
741#[cfg(test)]
742mod tests {
743 use crate::transport::IoBuffers;
744 use std::collections::VecDeque;
745 use vm_memory::{
746 bitmap::{AtomicBitmap, Bitmap},
747 VolatileSlice,
748 };
749
750 #[test]
751 fn test_io_buffers() {
752 let mut buf1 = vec![0x0u8; 16];
753 let mut buf2 = vec![0x0u8; 16];
754 let mut bufs = VecDeque::new();
755 unsafe {
756 bufs.push_back(VolatileSlice::new(buf1.as_mut_ptr(), buf1.len()));
757 bufs.push_back(VolatileSlice::new(buf2.as_mut_ptr(), buf2.len()));
758 }
759 let mut buffers = IoBuffers {
760 buffers: bufs,
761 bytes_consumed: 0,
762 };
763
764 assert_eq!(buffers.available_bytes(), 32);
765 assert_eq!(buffers.bytes_consumed(), 0);
766
767 assert_eq!(
768 buffers.consume_for_read(2, |buf| Ok(buf[0].len())).unwrap(),
769 2
770 );
771 assert_eq!(buffers.available_bytes(), 30);
772 assert_eq!(buffers.bytes_consumed(), 2);
773
774 let mut buffers2 = buffers.split_at(10).unwrap();
775 assert_eq!(buffers.available_bytes(), 10);
776 assert_eq!(buffers.bytes_consumed(), 2);
777 assert_eq!(buffers2.available_bytes(), 20);
778 assert_eq!(buffers2.bytes_consumed(), 0);
779
780 assert_eq!(
781 buffers2
782 .consume_for_read(10, |buf| Ok(buf[0].len() + buf[1].len()))
783 .unwrap(),
784 10
785 );
786 assert_eq!(
787 buffers2
788 .consume_for_read(20, |buf| Ok(buf[0].len()))
789 .unwrap(),
790 10
791 );
792
793 let _buffers3 = buffers2.split_at(0).unwrap();
794 assert!(buffers2.split_at(1).is_err());
795 }
796
797 #[test]
798 fn test_mark_dirty() {
799 let mut buf1 = vec![0x0u8; 16];
800 let bitmap1 = AtomicBitmap::new(16, 2);
801
802 assert_eq!(bitmap1.len(), 8);
803 for i in 0..8 {
804 assert_eq!(bitmap1.is_bit_set(i), false);
805 }
806
807 let mut buf2 = vec![0x0u8; 16];
808 let bitmap2 = AtomicBitmap::new(16, 2);
809 let mut bufs = VecDeque::new();
810
811 unsafe {
812 bufs.push_back(VolatileSlice::with_bitmap(
813 buf1.as_mut_ptr(),
814 buf1.len(),
815 bitmap1.slice_at(0),
816 ));
817 bufs.push_back(VolatileSlice::with_bitmap(
818 buf2.as_mut_ptr(),
819 buf2.len(),
820 bitmap2.slice_at(0),
821 ));
822 }
823 let mut buffers = IoBuffers {
824 buffers: bufs,
825 bytes_consumed: 0,
826 };
827
828 assert_eq!(buffers.available_bytes(), 32);
829 assert_eq!(buffers.bytes_consumed(), 0);
830
831 assert_eq!(
832 buffers.consume_for_read(8, |buf| Ok(buf[0].len())).unwrap(),
833 8
834 );
835
836 assert_eq!(buffers.available_bytes(), 24);
837 assert_eq!(buffers.bytes_consumed(), 8);
838
839 for i in 0..8 {
840 assert_eq!(bitmap1.is_bit_set(i), false);
841 }
842
843 assert_eq!(
844 buffers
845 .consume(true, 16, |buf| Ok(buf[0].len() + buf[1].len()))
846 .unwrap(),
847 16
848 );
849 assert_eq!(buffers.available_bytes(), 8);
850 assert_eq!(buffers.bytes_consumed(), 24);
851 for i in 0..8 {
852 if i >= 4 {
853 assert_eq!(bitmap1.is_bit_set(i), true);
854 continue;
855 } else {
856 assert_eq!(bitmap1.is_bit_set(i), false);
857 }
858 }
859 for i in 0..8 {
860 if i < 4 {
861 assert_eq!(bitmap2.is_bit_set(i), true);
862 } else {
863 assert_eq!(bitmap2.is_bit_set(i), false);
864 }
865 }
866 }
867}