You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: pci.rs
    path of file: ./repos/kernel/src/arch/aarch64/kernel
    
    the code of the file until where you have to start completion: use alloc::vec::Vec;
use core::{str, u32, u64, u8};

use arm_gic::gicv3::{IntId, Trigger};
use bit_field::BitField;
use hermit_dtb::Dtb;
use pci_types::{
	Bar, ConfigRegionAccess, InterruptLine, InterruptPin, PciAddress, PciHeader, MAX_BARS,
};

use crate::arch::aarch64::kernel::interrupts::GIC;
use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags};
use crate::arch::aarch64::mm::{virtualmem, PhysAddr, VirtAddr};
use crate::drivers::pci::{PciCommand, PciDevice, PCI_DEVICES};
use crate::kernel::boot_info;

const PCI_MAX_DEVICE_NUMBER: u8 = 32;
const PCI_MAX_FUNCTION_NUMBER: u8 = 8;

#[derive(Debug, Copy, Clone)]
pub(crate) struct PciConfigRegion(VirtAddr);

impl PciConfigRegion {
	pub const fn new(addr: VirtAddr) -> Self {
		assert!(addr.as_u64() & 0xFFFFFFF == 0, "Unaligned PCI Config Space");
		Self(addr)
	}

	#[inline]
	fn addr_from_offset(&self, pci_addr: PciAddress, offset: u16) -> usize {
		assert!(offset & 0xF000 == 0, "Invalid offset");
		(u64::from(pci_addr.bus()) << 20
			| u64::from(pci_addr.device()) << 15
			| u64::from(pci_addr.function()) << 12
			| (u64::
    
fn detect_pci_regions(dtb: &Dtb<'_>, parts: &[&str]) -> (u64, u64, u64) {
	let mut io_start: u64 = 0;
	let mut mem32_start: u64 = 0;
	let mut mem64_start: u64 = 0;

	let mut residual_slice = dtb.get_property(parts.first().unwrap(), "ranges").unwrap();
	let mut value_slice;
	while !residual_slice.is_empty() {
		(value_slice, residual_slice) = residual_slice.split_at(core::mem::size_of::<u32>());
		let high = u32::from_be_bytes(value_slice.try_into().unwrap());
		(value_slice, residual_slice) = residual_slice.split_at(core::mem::size_of::<u32>());
		let _mid = u32::from_be_bytes(value_slice.try_into().unwrap());
		(value_slice, residual_slice) = residual_slice.split_at(core::mem::size_of::<u32>());
		let _low = u32::from_be_bytes(value_slice.try_into().unwrap());

		match high.get_bits(24..=25) {
			0b00 => debug!("Configuration space"),
			0b01 => {
				debug!("IO space");
				if io_start != 0 {
					warn!("Found already IO space");
				}

				(value_slice, residual_slice) =
					residual_slice.split_at(core::mem::size_of::<u64>());
				io_start = u64::from_be_bytes(value_slice.try_into().unwrap());
			}
			0b10 => {
				let prefetchable = high.get_bit(30);
				debug!("32 bit memory space: prefetchable {}", prefetchable);
				if mem32_start != 0 {
					warn!("Found already 32 bit memory space");
				}

				(value_slice, residual_slice) =
					residual_slice.split_at(core::mem::size_of::<u64>());
				mem32_start = u64::from_be_bytes(value_slice.try_into().unwrap());
			}
			0b11 => {
				let prefetchable = high.get_bit(30);
				debug!("64 bit memory space: prefetchable {}", prefetchable);
				if mem64_start != 0 {
					warn!("Found already 64 bit memory space");
				}

				(value_slice, residual_slice) =
					residual_slice.split_at(core::mem::size_of::<u64>());
				mem64_start = u64::from_be_bytes(value_slice.try_into().unwrap());
			}
			_ => panic!("Unknown space code"),
		}

		// currently, the size is ignores
		(value_slice, residual_slice) = residual_slice.split_at(core::mem::size_of::<u64>());
		//let size = u64::from_be_bytes(value_slice.try_into().unwrap());
	}

	(io_start, mem32_start, mem64_start)
}