use std::num::NonZeroUsize;
use win_sys::*;
use winapi::um::errhandlingapi::GetLastError;
use super::{SegmentCreateError, SegmentID, SegmentOpenError, ShmCreateResult, ShmOpenResult};
pub struct SegmentImpl<ID: SegmentID> {
_fd: FileMapping,
len: NonZeroUsize,
data_ptr: ViewOfFile,
id: ID,
}
impl<ID: SegmentID> SegmentImpl<ID> {
pub fn create(id: ID, len: NonZeroUsize) -> ShmCreateResult<Self> {
let fd = {
let id = Self::id_str(id);
let high_size = ((len.get() as u64 & 0xFFFF_FFFF_0000_0000_u64) >> 32) as _;
let low_size = (len.get() as u64 & 0xFFFF_FFFF_u64) as _;
tracing::trace!(
"CreateFileMapping({:?}, NULL, {:X}, {}, {}, '{}')",
INVALID_HANDLE_VALUE,
PAGE_READWRITE.0,
high_size,
low_size,
id,
);
let fd = CreateFileMapping(
INVALID_HANDLE_VALUE,
None,
PAGE_READWRITE,
high_size,
low_size,
id.as_str(),
)
.map_err(|e| match e.win32_error().unwrap() {
ERROR_ALREADY_EXISTS => SegmentCreateError::SegmentExists,
err_code => SegmentCreateError::OsError(err_code.0 as _),
})?;
if unsafe { GetLastError() } == ERROR_ALREADY_EXISTS.0 {
return Err(SegmentCreateError::SegmentExists);
}
fd
};
let (data_ptr, len) =
Self::map(&fd).map_err(|e| SegmentCreateError::OsError(e.win32_error().unwrap().0))?;
let len = len
.try_into()
.map_err(|_e| SegmentCreateError::OsError(0))?;
Ok(Self {
_fd: fd,
len,
data_ptr,
id,
})
}
pub fn open(id: ID) -> ShmOpenResult<Self> {
let fd = {
let id = Self::id_str(id);
tracing::trace!(
"OpenFileMappingW({:?}, {}, '{}')",
FILE_MAP_ALL_ACCESS,
false,
id,
);
OpenFileMapping(FILE_MAP_ALL_ACCESS, false, id.as_str())
.map_err(|e| SegmentOpenError::OsError(e.win32_error().unwrap().0))
}?;
let (data_ptr, len) =
Self::map(&fd).map_err(|e| SegmentOpenError::OsError(e.win32_error().unwrap().0))?;
let len = len
.try_into()
.map_err(|_| SegmentOpenError::InvalidatedSegment)?;
Ok(Self {
_fd: fd,
len,
data_ptr,
id,
})
}
pub fn id(&self) -> ID {
self.id
}
pub fn len(&self) -> NonZeroUsize {
self.len
}
pub fn as_ptr(&self) -> *mut u8 {
self.data_ptr.as_mut_ptr() as _
}
}
impl<ID: SegmentID> SegmentImpl<ID> {
fn id_str(id: ID) -> String {
format!("{}.zenoh", id)
}
fn map(fd: &FileMapping) -> Result<(ViewOfFile, usize), Error> {
let data_ptr = {
tracing::trace!(
"MapViewOfFile(0x{:X}, {:X}, 0, 0, 0)",
fd,
(FILE_MAP_READ | FILE_MAP_WRITE).0,
);
MapViewOfFile(fd.as_handle(), FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0)
}?;
let len = {
let mut info = MEMORY_BASIC_INFORMATION::default();
VirtualQuery(data_ptr.as_mut_ptr(), &mut info)?;
info.RegionSize
};
Ok((data_ptr, len))
}
}